这是我参与更文挑战的第6天,活动详情查看:更文挑战
Spring提供了一种叫做BeanFactoryPostProcessor的容器机制。该机制允许我们在容器实例化相应对象之前,对注册到容器的BeanDefinition所保存的信息做相应的修改。这就相当于在容器实现的第一阶段最后加入一道工序,让我们对最终的BeanDefinition做一些额外的操作,比如修改其中bean定义的某些属性,为bean定义增加其他信息等。
如果要自定义实现BeanFactoryPostProcessor,我们需要实现org.springframework.beans.factory.config.BeanFactoryPostProcessor接口。同时一个容器可能拥有多个BeanFactoryPostProcessor,这个时候可能需要实现类同时实现Spring的org.springframework.core.Ordered接口,以保证各个BeanFactoryPostProcessor可以按照预先设定的顺序执行(如果顺序紧要的话)。但是,因为Spring已经提供了几个现成的BeanFactoryPostProcessor实现类,大多数时候,我们很少自己去实现某个BeanFactoryPostProcessor。其中,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer和org.springframework.beans.factory.config.PropertyOverrideConfigurer是两个比较常用的BeanFactoryPostProcessor。
1.PropertyPlaceholderConfigurer
通常情况下,我们不想将类似与系统管理相关的信息同业务对象相关的配置信息混杂到XML配置文件中,以免部署或者维护期间因为改动繁杂的XML配置文件而出现问题。我们会将一些数据库连接信息、邮件服务器等相关信息单独配置到一个properties配置文件中,这样,如果因系统资源变动的话,只需要关注这些简单的properties配件文件即可。
PropertyPlaceholderConfigurer允许我们在XML配置文件中使用占位符(PlaceHolder),并将这些占位符所代表的资源单独配置到简单的properties文件中来加载。以数据源的配置为例:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="url">
<value>${jdbc.url}</value>
</property>
<property>
<value>${jdbc.driver}</value>
</property>
<property>
<value>${jdbc.username}</value>
</property>
<property>
<value>${jdbc.password}</value>
</property>
<properry name="maxActive">
<value>100</value>
</properry>
</bean>
复制代码
现在,所以这些占位符所代表的资源,都放到了jdbc.properties文件中,如下所示:
jdbc.url=jbcd:mysql://...
jdbc.driver=com.mysql.jdbc.Driver
jdbc.username=your username
jdbc.password=your password
复制代码
基本机制就是之前所说的那样。当BeanFactory在第一阶段加载完成所有配置信息时,BeanFactory中所保存的对象的属性信息还只是以占位符的形式存在,如${jdbc.url}
。当PropertyPlaceholderConfigurer作为BeanFactoryPostProcessor被应用时,它会使用properties配置文件中的配置信息来替换相应的BeanDefinition中占位符所表示的属性值。这样,当进入容器实现的第二阶段实例化bean时,bean定义中的属性值就是最终替换完成的了。
2.PropertyOverrideConfigurer
如果说,PropertyPlaceholderConfigurer做的这些是“明事”的话,那相对来说,PropertyOverrideConfigurer所做的就有点“神不知鬼不觉”了。可以通过PropertyPlaceholderConfigurer对容器中配置的任何你想处理的bean定义的property信息进行覆盖替换。比如之前的dataSource定义中,maxActive的值为100,如果我们觉得不合适,那么可以通过PropertyPlaceholderConfigurer在其相应的properties文件中做dataSource.maxActive=200
,来把100覆盖掉。
PropertyPlaceholderConfigurer文件中配置项,覆盖掉了原来XML中的bean定义的property信息。但这样的活动,只看XML配置的话,根本看不出哪个bean定义的property会被覆盖替换掉,只有查看PropertyPlaceholderConfigurer指定的properties配置文件才会了解。基本上,这种覆盖替换对于bean定义来说是透明的。
如果要对容器中的某些bean定义的property信息进行覆盖,我们需要按照如下规则提供一个PropertyOverrideConfigurer使用的配置文件:beanName.propertyName=value