Spring知识整理(六)—— IoC容器扩展(上)

在了解了BeanFactory和Application这两个IoC容器之后,我们从整体上对IoC容器进行一下总结。首先Spring的IoC容器可以分为两个部分,其核心是IoC Service Provider,用于提供基本的IoC支持。此外还有一些其它的功能,包括线程管理、对象生命周期管理、企业服务集成和AOP支持等等。

 

IoC Service Provider

先来看下IoC Service Provider,它的主要功能就是对象的构建管理和依赖绑定。IoC Service Provider是一个抽象概念,它可以指任何将IoC中的业务对象绑定到一起的实现方式。IoC Service Provider需要依赖如配置文件、注解或者直接编码的方式来完成依赖管理。

 

IoC Service Provider只是一个概念,如果想了解依赖绑定究竟是怎么完成的,可以去看下DefaultListableBeanFactory类中的getBean方法的原码,这里就不多说了。

 

Bean scope

对于Bean来说,也有scope的概念。对于简单的应用,Spring提供了两种bean的scope:singleton(单例)和prototype(原型)。这两个scope都很好理解,单例就是多个调用共享一个对象,原型就是每次引用都重新声称新的对象。配置也十分简单,直接在bean标签中加入scope="prototype/singleton"属性即可。对于Web应用,Spring2.0开始新加入了三个scope:request、session和global session,这个放到以后再说。

 

IoC容器功能实现过程

Spring的IoC容器实现构建管理和依赖绑定功能的过程,可以划分为两个阶段,即容器启动阶段和Bean实例化阶段:
Spring知识整理(六)—— IoC容器扩展(上)
 

在容器的启动阶段,加载配置、分析配置信息和装配都是容器内部已经规划好的,也就是说这部分代码我们只能拿过来用。分析好的配置信息会保存在BeanDefinition中,再注册到对应的BeanDefinitionRegistry(DefaultListableBeanFactory实现的接口之一)以完成装配。

 

那么对于容器的启动,我们可以做一些自定义处理的就是后处理阶段了。Spring提供了BeanFactoryPostProcessor接口作为容器扩展机制。该机制允许我们在容器实例化对象之前,对BeanDefinition的信息做相应的修改。一个容器可以有多个BeanFactoryPostProcessor,它们的顺序由Ordered接口决定(多个BeanFactoryPostProcessor时必须实现Ordered接口)。

 

Spring提供了三种比较常用的BeanFactoryPostProcessor实现:

PropertyPlaceholderConfigurer:名字一目了然,可以在Spring配置文件中使用占位符(形式为${xxx.xxx})代替属性的值,这些值可以在properties文件中找到,方便维护和更新。

所要做的就是在代码中为BeanFactory装配:

// 声明将被后处理的BeanFactory实例
ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("..."));
// 声明要使用的BeanFactoryPostProcessor 
PropertyPlaceholderConfigurer propertyPostProcessor = new PropertyPlaceholderConfigurer();
propertyPostProcessor.setLocation(new ClassPathResource("..."));
// 执行后处理操作 
propertyPostProcessor.postPro 4cessBeanFactory(beanFactory);

 

或者在配置文件中指明(仅适用于ApplicationContext):

 

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
     <property name="locations">
           <list>
                <value>conf/jdbc.properties</value>
                <value>conf/mail.properties</value> 
           </list>
      </property>
</bean>

 

同时,PropertyPlaceholderConfigurer还会检查Java的System类中的Properties,可以通过setSystemPropertiesMode()或者setSystemPropertiesModeName()来控制是否加载或者覆盖System相应Properties的行为。PropertyPlaceholderConfigurer提供了SYSTEM_PROPERTIES_MODE_FALLBACK、SYSTEM_PROPERTIES_MODE_NEVER和SYSTEM_PROPERTIES_MODE_OVERRIDE三种模式,默认采用的是SYSTEM_PROPERTIES_ MODE_FALLBACK。

 

PropertyOverrideConfigurer:相对于上面一种BeanFactoryPostProcessor,PropertyOverrideConfigurer的做法就很难在Spring的配置文件中观察出来,因为只要你用了PropertyOverrideConfigurer,那么它只会根据其properties文件内容对属性进行覆盖,其properties文件内容的格式如下

beanName.propertyName=value

也就是说你在properties文件中配了某一个属性的值,那么在此之前,你无论是用写死的值还是占位符,最后的值都会被这个文件中对应的值覆盖掉。

 

CustomEditorConfigurer:这个BeanFactoryPostProcessor只是辅助性地将后期会用到的信息注册到容器,对BeanDefinition不会做任何变动。它是帮助传达一种转换规则,就是将XML中的字符串转换到对应类型的规则。当然Spring提供了一系列的PropertyEditor,用于转换String,大部分在于org.springframework.beans.propertyeditors包内,可自行参考。

 

我们可以自定义PropertyEditor,首先需要的是继承PropertyEditorSupport,复写setAsText方法,然后通过类似如下的代码通过CustomEditorConfigurer将自定义的PropertyEditor注册到容器:

XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(…));

CustomEditorConfigurer ceConfigurer = new CustomEditorConfigurer();
Map customerEditors = new HashMap();
customerEditors.put(java.util.Date.class, new XXXPropertyEditor());
ceConfigurer.setCustomEditors(customerEditors);

ceConfigurer.postProcessBeanFactory(beanFactory);

 

当然,使用ApplicationContex时会自动识别BeanFactoryPostProcessor,所以只要在配置文件中定义对应的Bean即可。

相关推荐