Spring揭秘2:IOC容器之BeanFactory

本文介绍了如何使用Spring的BeanFactory通过XML配置文件实现业务对象间依赖管理,包括构造方法注入和setter方法注入,以及使用Properties文件和默认的BeanDefinitionReader。
摘要由CSDN通过智能技术生成

BeanFactory

使用BeanFactory的XML配置方式实现业务对象间的依赖管理

<beans>
    <bean id="djNewsProvider" class="..FXNewsProvider">
        <constructor-arg index="0">
            <ref bean="djNewsListener"/>
        </constructor-arg>
        <constructor-arg index="1">9
            <ref bean="djNewsPersister"/>
        </constructor-arg>
    </bean>
    ...
</beans> 

具体使用:

    BeanFactory container = new XmlBeanFactory(new ClassPathResource("配置文件路径")); 
    FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");  
    newsProvider.getAndPersistNews(); 
    // 或者
    ApplicationContext container = new ClassPathXmlApplicationContext("配置文件路径"); 
    FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider"); 
    newsProvider.getAndPersistNews();

依赖关系管理:对象注册与依赖绑定方式

1. 直接编码

main方法中:

  1. 构造一个 DefaultListableBeanFactory 作 为 BeanDefinitionRegistry
  2. 将其交给bindViaCode方法进行具体的对象注册和相关依赖管理
  3. 通过bindViaCode返回的BeanFactory取得需要的对象,最后执行相应逻辑

bindViaCode方法中:

  1. 构造业务对象与其相对应的BeanDefinition,使用了 RootBeanDefinition 作 为 BeanDefinition 的实现类。
  2. 构造完成后,将这些BeanDefinition注册到通过方法参数传进来的BeanDefinitionRegistry中。
  3. 指定依赖关系:构造方法注入,setter方法注入。
    public static void main(String[] args) {
        // 构造一个DefaultListableBeanFactory作为BeanDefinitionRegistry
        DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
        // 交给bindViaCode进行具体对象的注册和依赖管理
        BeanFactory container = (BeanFactory) bindViaCode(beanRegistry);
        // 通过bindViaCode返回的BeanFactory取得需要的对象
        FXNewsProvider newsProvider = (FXNewsProvider) container.getBean("djNewsProvider");
        newsProvider.getAndPersistNews();
    }

    public static BeanFactory bindViaCode(BeanDefinitionRegistry registry) {
        // 构造业务对象对应的BeanDefinition
        AbstractBeanDefinition newsProvider = new RootBeanDefinition(FXNewsProvider.class, true);
        AbstractBeanDefinition newsListener = new RootBeanDefinition(DowJonesNewsListener.class, true);
        AbstractBeanDefinition newsPersister = new RootBeanDefinition(DowJonesNewsPersister.class, true);
        // 将bean定义注册到容器中
        registry.registerBeanDefinition("djNewsProvider", newsProvider);
        registry.registerBeanDefinition("djListener", newsListener);
        registry.registerBeanDefinition("djPersister", newsPersister);
        
        /**
        * 指定依赖关系:1.构造方法注入 2.setter方法注入
        */
        // 1. 可以通过构造方法注入方式
        ConstructorArgumentValues argValues = new ConstructorArgumentValues();
        argValues.addIndexedArgumentValue(0, newsListener);
        argValues.addIndexedArgumentValue(1, newsPersister);
        newsProvider.setConstructorArgumentValues(argValues);
        // 2. 或者通过setter方法注入方式
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.addPropertyValue(new ropertyValue("newsListener", newsListener));
        propertyValues.addPropertyValue(new PropertyValue("newPersistener", newsPersister));
        newsProvider.setPropertyValues(propertyValues);
        // 绑定完成
        return (BeanFactory) registry;
    }

DefaultListableBeanFactory:BeanFactory的实现类

在这里插入图片描述

  • BeanFactory接口只定义如何访问容器内管理的Bean的方法,各个BeanFactory的具体实现类负责具体Bean的注册以及管理工作

  • BeanDefinitionRegistry接口定义抽象了Bean的注册逻辑

通常情况下,具体的BeanFactory实现类会实现这个接口来管理Bean的注册。

BeanFactory、BeanDefinitionRegistry以及DefaultListableBeanFactory的关系

在这里插入图片描述

BeanDefinitionRegistry 管理 BeanDefinition

每一个受管的对象,在容器中都会有一个BeanDefinition的实例(instance)与之相对应,该 BeanDefinition的实例负责保存对象的所有必要信息,【包括其对应的对象的class类型、是否是抽象 类、构造方法参数以及其他属性等】。

当客户端向BeanFactory请求相应对象的时候,BeanFactory会通过这些信息为客户端返回一个完备可用的对象实例。RootBeanDefinitionChildBeanDefinition是BeanDefinition的两个主要实现类。

2. 外部配置文件

Spring的IoC容器支持两种配置文件格式:Properties文件格式和XML文件格式。

采用外部配置文件时,Spring的IoC容器有一个统一的处理方式。

  1. 通常情况下,需要根据不同的外部配置文件格式,给出相应的BeanDefinitionReader实现类
  2. 由BeanDefinitionReader的相应实现类负责将相应的配置文件内容读取并映射到BeanDefinition:包括解析文件格式、装配BeanDefinition之类的工作,都是由BeanDefinitionReader的相应实现类来做的
  3. 将映射后的BeanDefinition注册到一个BeanDefinitionRegistry:BeanDefinitionRegistry只不过负责保管而已
  4. BeanDefinitionRegistry即完成Bean的注册和加载
    BeanDefinitionRegistry beanRegistry = <某个BeanDefinitionRegistry实现类,通常为DefaultListableBeanFactory>; 
    BeanDefinitionReader beanDefinitionReader = new BeanDefinitionReaderImpl(beanRegistry); 
    beanDefinitionReader.loadBeanDefinitions("配置文件路径"); 
    // 现在我们就取得了一个可用的Bea nDefinitionRegistry实例

1. Properties配置格式的加载

Spring提供了org.springframework.beans.factory.support.PropertiesBeanDefinitionReader类用于Properties格式配置文件的加载,所以,我们不用自己去实现BeanDefinitionReader, 只要根据该类的读取规则,提供相应的配置文件即可。

djNewsProvider.(class)=..FXNewsProvider 
# ----------通过构造方法注入的时候------------- 
djNewsProvider.$0(ref)=djListener 
djNewsProvider.$1(ref)=djPersister 
# ----------通过setter方法注入的时候--------- 
djNewsProvider.newsListener(ref)=djListener 
djNewsProvider.newPersistener(ref)=djPersister 
djListener.(class)=..impl.DowJonesNewsListener 
djPersister.(class)=..impl.DowJonesNewsPersister

这些内容是特定于Spring的PropertiesBeanDefinitionReader的,要了解更多内容,请参照Spring的API参考文档。

  • djNewsProvider作为beanName,后面通过.(class)表明对应的实现类是什么。其他两个类的注册,djListener和djPersister,也是相同的道理。
  • 通过在表示beanName的名称后添加.$[number]后缀的形式,来表示当前beanName对应的对象需要通过构造方法注入的方式注入相应依赖对象。在这里,我们分别将构造方法的第一个参数和第二个参数对应到djListener和djPersister。需要注意的一点,就是$0和$1后面的 (ref),(ref)用来表示所依赖的是引用对象,而不是普通的类型。如果不加(ref), PropertiesBeanDefinitionReader会将djListener和djPersister作为简单的String类型 进行注入。
  • 构造方法注入方式:FXNewsProvider采用的是构造方法注入
  • setter方法注入与构造方法注入最大的区别就是,它不使用数字顺序来指定注入的位置,而使用相应的属性名称来指定注入。newsListenernewPersistener恰好就是我们的FXNewsProvider类中所声明的属性名称。与在 Properties中表达构造方法注入一样,同样需要注意,如果属性名称所依赖的是引用对象,那 么一定不要忘了**(ref)**。

当这些对象之间的注册和依赖注入信息都表达清楚之后,就可以将其加载到BeanFactory而付诸使用了。

    public static void main(String[] args) {
        DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
        BeanFactory container = (BeanFactory) bindViaPropertiesFile(beanRegistry);
        FXNewsProvider newsProvider = (FXNewsProvider) container.getBean("djNewsProvider");
        newsProvider.getAndPersistNews();
    }

    public static BeanFactory bindViaPropertiesFile(BeanDefinitionRegistry registry) {
        PropertiesBeanDefinitionReader reader = new PropertiesBeanDefinitionReader(registry);
        reader.loadBeanDefinitions("classpath:../../binding-config.properties");
        return (BeanFactory) registry;
    }
2. xml配置格式的加载
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
        "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="djNewsProvider" class="..FXNewsProvider">
        <constructor-arg index="0">
            <ref bean="djNewsListener"/>
        </constructor-arg>
        <constructor-arg index="1">
            <ref bean="djNewsPersister"/>
        </constructor-arg>
    </bean>

    <bean id="djNewsListener" class="..impl.DowJonesNewsListener">
    </bean>
    <bean id="djNewsPersister" class="..impl.DowJonesNewsPersister">
    </bean>
</beans>

具体使用

    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"));
    }
  1. Spring同样为XML 格式的配置文件提供了现成的BeanDefinitionReader实现,即XmlBeanDefinitionReader。
  2. XmlBeanDefinitionReader负责读取Spring指定格式的XML配置文件并解析
  3. 将解析后的文件内容映射到相应的BeanDefinition,并加载到相应的BeanDefinitionRegistry中(在这里是DefaultListableBeanFactory)
  4. 整个BeanFactory就可以放给客户端使用了

Spring除了提供XmlBeanDefinitionReader用于XML格式配置文件的加载,Spring还在DefaultListableBeanFactory的基础上构建了简化XML格式配置加载的XmlBeanFactory实现。从以上代码最后注释掉的一行,你可以看到使用了XmlBeanFactory之后,完成XML的加载和BeanFactory的初始化是多么简单。

3. 注解方式

如果要通过注解标注的方式为FXNewsProvider注入所需要的依赖,现在可以使用**@Autowired以 及@Component**对相关类进行标记。

@Autowired是这里的主角,它的存在将告知Spring容器需要为当前对象注入哪些依赖对象。

@Component则是配合Spring 2.5中新的classpath-scanning功能使用的。该类交给spring管理的标志。现在我们只要再向Spring的配置 文件中增加一个“触发器”,使用@Autowired和@Component标注的类就能获得依赖对象的注入了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值