zoukankan      html  css  js  c++  java
  • spring揭秘读书笔记----spring的ioc容器之BeanFactory

    spring的ioc容器是一种特殊的Ioc Service Provider(ioc服务提供者),如果把普通的ioc容器认为是工厂模式(其实很相似),那spring的ioc容器只是让这个工厂的功能更强大服务更全面,它们之间存在一定的交集。
     
    Spring提供两种容器类型:BeanFactory和ApplicationContext
    BeanFatory:基础类型IoC容器,提供完整的IoC服务支持。默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管理对象的时候,才对该受管对象进行初始化以及依赖注入操作。相对来说,容器启动初期速度较快,所需要的资源有限。
    ApplicationContext:基于BeanFactory,相对比较高级的容器实现。相比BeanFactory要求更多的系统资源,启动时候较长,但是拥有事件发布、国际化等高级特性。
     作为Spring提供的基本的Ioc容器,BeanFactory可以完成作为Ioc Service Provider的所有职责,包括业务对象的注册和对象建依赖关系的绑定。
    BeanFactory就像一个汽车生产厂,你只需告诉它你需要哪些零件,然后在生产线的终点取得成品汽车就可以了。所以对于客户端来说,与BeanFactory打交道很简单。来看下源码:
    public interface BeanFactory {
    
        String FACTORY_BEAN_PREFIX = "&";
    
        Object getBean(String name) throws BeansException;
    
        <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    
        <T> T getBean(Class<T> requiredType) throws BeansException;
    
        Object getBean(String name, Object... args) throws BeansException;
    
        boolean containsBean(String name);
    
        boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    
        boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    
        boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
    
        Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    
        String[] getAliases(String name);
    
    }

    我们应用的时候只用关心如何取得组装完成的对象的接口,即getBean()方法,这里提供了不同的参数以满足各种情况。所有对象之间的依赖关系就由BeanFactory来做了,那么如何做呢?

    首先,通过xml告诉BeanFactory对象之间的依赖关系:

    <beans>
        <bean id="djNewsProvider" class=".../FXNewsProvider"></bean>
       ...
    </beans>

    然后BeanFactory就可以按照配置文件来注册对象和绑定依赖了:

    BeanFactory container = new XmlBeanFactory(new ClassPatnResource("配置文件路径"));
    FXNewsProvider djNewsProvider  = (FXNewsProvider)container.getBean("djNewsProvider"); 
    djNewsProvider.getAndPersistNews();

    BeanFactory的三种对象注册与依赖绑定方式:

    1.直接编码

    BeanFactory接口只定义如何访问容器内管理的Bean的方法,还需要具体实现类来负责Bean的注册及管理工作。

    DefaultListableBeanFactory间接地实现了BeanFactory和BeanDefinitionRegistry接口。它们之间的关系如下:

    打个比方,BeanDefinitionRegistry就像图书馆的书架,所有的书是放在书架上的。虽然你还书或者借书都是跟图书馆(也就是BeanFactory,或许BookFactory可能更好些)打交道,但书架才是图书馆存放各类图书的地方。所以,书架相对于图书馆来说,就是它的“BookDefinitionRegistry”。

    每一个受管的对象,在容器中都会有一个BeanDefinition的实例(instance)与之相对应,该BeanDefinition的实例负责保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象类、构造方法参数以及其他属性等。当客户端向BeanFactory请求相应对象的时候,BeanFactory会通过这些信息为客户端返回一个完备可用的对象实例。

    2.外部配置文件(两种格式:Properties和xml)

    这种方式还是由BeanDefinitionRegistory负责管理注册的bean,不过解析文件、装配BeanDefinition等工作都由BeanDefinitionReader实现类完成。模拟xml配置文件流程:

    public static void main(String[] args)
    {
        DefaultListableBeanFactory beanRegistry = new    DefaultListableBeanFactory();
        BeanFactory container = (BeanFactory)bindViaXMLFile(beanRegistry);
        FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");
        newsProvider.getAndPersistNews(); 
    }
    
    public static BeanFactory bindViaXMLFile(BeanDefinitionRegistry registry)
    {
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
        reader.loadBeanDefinitions("classpath:../news-config.xml");
       return(BeanFactory)registry;
      // 或者直接 
      //return new XmlBeanFactory(new ClassPathResource("../news-config.xml"));
    }

    3.注解方式

    @Component
    public class FXNewsProvider{
        @Autowired
        private IFXNewsListener newsListener;
        @Autowired
        private IFXNewsPersister newPersistener;
        public FXNewsProvider(IFXNewsListener newsListner,IFXNewsPersister newsPersister)
      {
          this.newsListener = newsListner;
          this.newPersistener = newsPersister;
      }
      ...
    }    

    @Autowired是这里的主角,它的存在将告知Spring容器需要为当前对象注入哪些依赖对象。而@Component则是配合Spring 2.5中新的classpath-scanning功能使用的。现在我们只要再向Spring的配置文件中增加一个“触发器”,使用@Autowired和@Component标注的类就能获得依赖对象的注入了。需要配置文件:

    <context:component-scan base-package="cn.spring21.project.base.package"/></beans>

    <context:component-scan/>会到指定的包(package)下面扫描标注有@Component的类,如果找到,则将它们添加到容器进行管理,并根据它们所标注的@Autowired为这些类注入符合条件的依赖对象。

    然后就可以像之前加载配置文件一样的方式执行当前应用程序了:

    public static void main(String[] args){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("配置文件路径");
        FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("FXNewsProvider");4.3 
        newsProvider.getAndPersistNews();
    }

    整体来看spring Ioc容器
    spring的Ioc容器的作用是以某种方式加载配置信息,然后根据这些信息绑定整个系统的对象,最终组装成一个可用的基于轻量级容器的应用系统。这个过程可以分为两个阶段:容器启动和Bean实例化。Spring的IoC容器在实现的时候,充分运用了这两个实现阶段的不同特点,在每个阶段都加入了相应的容器扩展点,以便我们可以根据具体场景的需要加入自定义的扩展逻辑。

    1. 容器启动阶段
    容器启动伊始,首先会通过某种途径加载Configuration MetaData。除了代码方式比较直接,在大部分情况下,容器需要依赖某些工具类(BeanDefinitionReader)对加载的Configuration MetaData进行解析和分析,并将分析后的信息编组为相应的BeanDefinition,最后把这些保存了bean定义必要信息的BeanDefinition,注册到相应的BeanDefinitionRegistry,这样容器启动工作就完成了。

    总地来说,该阶段所做的工作可以认为是准备性的,重点更加侧重于对象管理信息的收集。当然,一些验证性或者辅助性的工作也可以在这个阶段完成。

    2. Bean实例化阶段
    经过第一阶段,现在所有的bean定义信息都通过BeanDefinition的方式注册到了BeanDefinitionRegistry中。当某个请求方通过容器的getBean方法明确地请求某个对象,或者因依赖关系容器需要隐式地调用getBean方法时,就会触发第二阶段的活动。该阶段,容器会首先检查所请求的对象之前是否已经初始化。如果没有,则会根据注册的BeanDefinition所提供的信息实例化被请求对象,并为其注入依赖。如果该对象实现了某些回调接口,也会根据回调接口的要求来装配它。当该对象装配完毕之后,容器会立即将其返回请求方使用。如果说第一阶段只是根据图纸装配生产线的话,那么第二阶段就是使用装配好的生产线来生产具体的产品了。

    总结:本节主要介绍了spring的两种容器类型,然后又介绍了最基本的BeanFactory的三种对象注册和依赖绑定方式,其实和一般的Ioc Service Provider支持的三种方式一样。

  • 相关阅读:
    O(1)时间复杂度实现入栈、出栈、获得栈中最小元素、获得栈中最大元素(转)
    北京网选赛第二题(最大仰望角度)
    最小圆覆盖(随机增量法&模拟退火法)
    模拟退火算法A Star not a Tree?(poj2420)
    模拟退火算法(run away poj1379)
    模拟退火算法(西安网选赛hdu5017)
    最小费用流判负环消圈算法(poj2175)
    中国邮递员问题(一)
    破坏行动问题
    进化树问题
  • 原文地址:https://www.cnblogs.com/hechao123/p/7120203.html
Copyright © 2011-2022 走看看