读书笔记--spring解密---spring中的IoC容器

Spring的IoC容器就是一个 IoC service provider.  但是它提供的又不仅仅是IoC service provider的功能,还包括:对象生命周期管理,线程管理,企业服务集成,AOP支持,等等。

 

Spring提供了2种IoC容器:

  1. BeanFactory:基础类型的IoC容器,能够完成IoC的所有功能。 采用延迟加载(lazy load),只有客户端需要某个对象时才进行构建和依赖注入。 容器自身加载快,一开始需要的资源少。
  2. ApplicationContext:它是基于BeanFactory的一种高级的IoC容器。除了提供IoC的基本功能外,还提供了消息通知等其他功能。 它在加载时,将初始化所有业务对象,并进行依赖注入。

 

BeanFactory中,对象注册和依赖绑定的实现方式

之前我们学习到,有3种绑定方式,这3种方式BeanFactory都是支持的,我们一个一个看看。

  1. 直接编码方式。 实际上,任何一种方式最后都得进行编码,只是编码工作由不同的人做而已。我们这里研究直接编码,只是想学习一下BeanFactory的实现原理
    public static void main(String[] args){
        //DefaultListableBeanFactory是BeanFactory接口的一个默认实现,它同时实现了BeanFactory和BeanDefinitionRegistry两个接口。
        DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
        BeanFactory container = (BeanFactory) bindViaCode(beanRegistry);
        FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");
        newsProvider.getAndPersistNews();
    
    }
    
    
    public static BeanFactory bindViaCode(BeanDefinitionRegistry registry){
        //RootBeanDefinition是AbstractBeanDefinition的一个实现,用来保存业务类的相关信息,例如类型,初始化参数等。AbstractBeanDefinition实现了BeanDefinition接口。
        AbstractBeanDefinition newsProvider = new RootBeanDefinition(FXNewsProvider.class, true);
    
        AbstractBeanDefinition newsListener = new RootBeanDefinition(DownJonesNewsListener.class, true);
    
        AbstractBeanDefinition newsPersistenter = new RootBeanDefinition(DownJonesPersistenter.class, true);
    
        //将bean的定义注册到容器中
        register.registerBeanDefinition("djNewsProvider", newsProvider);
        register.registerBeanDefinition("djNewsListener", newsListener);
        register.registerBeanDefinition("djNewsPersistenter", newsPersistenter);
    
    
        //进行绑定操作,这里提供的是通过构造函数绑定时需要的信息
        ConstructorArgumentsValue argValues = new ConstructorArgumentsValue();
        argValues.addIndexedArgumentValue(0, newsListener);
        argValues.addIndexedArgumentValue(1, newsPersistenter);
    
        newsProvider.setConstructorArgumentValues(argValues);
    
        //因为同时实现了2个接口,这里才能进行这种强制转换的
        return (BeanFactory) registry;
    
    }
  2. 外部配置文件方式。spring支持2种文件,property文件和xml文件。采用外置配置文件时,spring的IoC提供了一个统一的处理流程。 大致流程是:根据配置文件的格式,选择一个BeanDefinitionReader接口的一个实现,负责读取配置文件的内容,并将其映射到BeanDefinition, 然后将这些BeanDefinition注册到BeanDefinitionRegistry中。这些工作的类似于上面的代码。Property文件,使用的是org.springframework.beans.factory.support.PropertysBeanDefinitionReader, 配置文件如下:
    #djNewsProvider是bean的名字,.(class)表明对应的实现类是什么
    djNewsProvider.(class)=..FXNewsProvider
    #通过构造函数进行注入,$后面的数字是构造函数参数的位置索引,(ref)表示所依赖的引用对象,如果不写ref会把djListener当做字符串的。
    djNewsProvider.$0(ref)=djListener
    djNewsProvider.$1(ref)=djPersistenter
    #通过setter注入
    #djNewsProvider.newsListener(ref)=djListener
    #djNewsProvider.newsPersistenter(ref)= djPersistenter
    
    djListener.(class)=..impl.DownJonesListener
    djPersistenter.(class)=..impl.DownJonesPersistenter
    

    Property文件的加载例子:

    public static void main(String[] args){
    
        DefaultListableBeanFactory registry = new DefaultListableBeanFactory();
        BeanFactory container = (BeanFactory)bindViaPropertiesFile(registry);
        
        FXNewsProvider provider = (FXNewsProvider) container.getBean("djNewsProvider");
        provider.getAndPersistentNews();
    
    }
    
    public static BeanFactory bindViaPropertiesFile(BeanDefinitionRegistry registry){
    
        PropertiesBeanDefinitionReader reader = new PropertiesBeanDefinitionReader(registry);
    
        reader.loadBeanDefinitions("classpath:../../xxx.properties");
    
        return (BeanFactory)registry;
    
    }

     

  3.  

  4. XmlBeanDefinitionReader则是用来读取xml文件的,过程代码与property的例子相似。另外,由于xml非常常用,所以spring又提供了一个累来简化加载配置文件的过程:return XmlBeanFactory(new ClassPathResource("../xxx.xml");

  5. 下面我们研究下xml文件编写过程可能遇到的问题:

  6. 使用构造函数时,如果类有2个构造函数,而且参数个数相同,但类型不同,这时我们需要使用type来确定调用哪个构造函数。但是如果有2个参数,怎么指定类型呢??

  7. <bean id="Mock" class="MockImpl">
        <constructor-arg type="int">
            <value>1111</value>
        </constructor-arg>
    
    </bean>
    
    
    <bean id="Mock" class="MockImpl">
        <constructor-arg type="int" value=1111/>
        <constructor-arg type="float" value=12.34/>
    
    </bean>

    如果有1个构造函数,它有2个参数,我们书写的时候,一定要注意安装参数的定义的顺序。如果不按照顺序,那怎么处理呢? 使用index,可以解决这个问题。

  8. <bean id="Mock" class="MockImpl">
        <constructor-arg index="0" value=111/>
        <constructor-arg index="1" value=222/>
    
    </bean>

     

  9. 使用setter注入时,spring提供了property,使用方式如下。我们需要为属性djNews和account生产setter方法。 实际上setter注入和构造注入是可以并存的,先构造,再调用setter注入。

  10. <bean id="Mock" class="MockImpl">
        <property name="djNews" ref="djNewsImpl"/>
        <property name="account" value=222/>
    
    </bean>
    
    <bean id="djNewsImpl" class="NewsImpl">
    
    </bean>

     

  11. 对于construtor-arg和property,除了我们上边用到过的ref和value,我们还可以使用其他元素来指定注入类型:bean,ref, idref,value,null,list,set,map,props。这些元素对于construtor-arg和property是通用的。

  12. 1. value:可以通过它注入基本数据类型,但是也可以指定String类型和基本类型的包装器类型。但是value是最底层元素,不能在嵌入任何东西了

  13. 2. ref:用来引用容器中的实例,它有三个属性,local parent 和 bean。其中local是说,我们要引用的实例就在当前配置文件所生成的容器中。 parent是指我们要引用的实例在当前容器的父容器中。bean呢,如果local找不到会去父容器找,所以这个选项比较常用。

    
    <bean id="theTargetBean" class="..."/>
     
    <bean id="theClientBean" class="...">
        <property name="targetName">
            <ref bean="theTargetBean" />
        </property>
    </bean>
    
    BeanFactory parentBeanFactory = new XmlBeanFactory(new ClassPathResource('parent.xml'));
    BeanFactory childBeanFactory = new XmlBeanFactory(new ClassPathResource('child.xml'), parentBeanFactory);
    

     

  14. 3. idref: 注入的是所依赖的对象的名称,是个字符串,不是对象实例哦! 它的效果与用value是一样的,不同的地方在与,使用idref的话,在解析xml会进行检查是不是有对象的名字叫这个。 如果使用value那么只有到运行时才会发现没有叫这个名字的对象。 idref也支持三个属性,local parent 和 bean

  15. 4. bean:这个bean与外面的bean支持的元素都是相同的,特殊的地方在与我们用它定义一个内部的,局域的bean,其他地方是看不到它的。 内部bean的id可以省略,因为没人会用它。

    
     
    <bean id="theClientBean" class="...">
        <property name="targetName">
            <bean id="theTargetBean" class="..."/>
        </property>
    </bean>

     

  16.  

  17.  

  18.  

  19. 注解方式,是java5和spring2.5之后才有的。 以后会详细介绍。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值