从源代码分析Spring处理property-placeholder原理
一、如何在Spring中将属性文件配置内容加载到环境中
1.1、在Spring的XML配置文件中配置<context:property-placeholder/>,由于<context:property-placeholder/>命名空间为
http://www.springframework.org/schema/context,通过命名空间名与处理程序的映射关系(Sping中配置的关系在sping.handlers文件中),
找到处理器http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
1.2、在ContextNamespaceHandler中的init()函数中注册了parser解析器this.registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
1.3、调用PropertyPlaceholderBeanDefinitionParser.parse()函数开始解析XML中配置的属性
1.4、在PropertyPlaceholderBeanDefinitionParser.parse()函数中调用了AbstractSingleBeanDefinitionParser.parseInternal()函数构建
构建内部BeanDefinition,最后调用了AbstractPropertyLoadingBeanDefinitionParser.doParse()函数解析property-placeholder自定义的属性
1.5、最后将构建好的BeanDefinition注册到BeanDefinitionRegistry注册中心*Spring上下文使用
二、如何使用加载到环境中的配置
2.1、Spring通过BeanFactoryProcessor进行扩展,Spring提供了PropertyPlaceholderConfigurer(其实现了BeanFactoryPostProcessor)
在Bean创建前将占位符使用配置文件中的配置值替换
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
或者
@Value("${spring_only}")
private String springOnly;
2.2、通过两种方式注入
Bean方式:
单个配置文件
<bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="location">
<value>conf/sqlmap/jdbc.properties</value>
</property>
<property name="fileEncoding">
<value>UTF-8</value>
</property>
</bean>
多个配置文件
<bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/mail.properties</value>
<value>classpath: conf/sqlmap/jdbc.properties</value>//注意这两种value值的写法
</list>
</property>
</bean>
标签方式:
<context:property-placeholder location="classpath*:/WEB-INF/mail.properties" />
今天一个问题困扰了我一下午,因此必须记录下来
在PropertyPlaceholderConfigurer类中的location、locations、localProperties分别为 Resource、Resource[]、Properties[]类型,
而XML中指定属性值时却是字符串类型,一直都不知道Spring在什么时候、通过哪种机制处理转换的(将字符串转换成Resource、Resource[]、Properties[])
研究了很久发现Spring提供了一些系统的属性编辑器(超类为PropertyEditorSupport),Spring在解析和赋值property时,会调用对应的编辑器处理
,且Spring会默认依据property的类型找对应的编辑器。比如Resource有对应的编辑器ResourceEditor,会将字符串值转换处理为Resource、Resource[]。
若想要改变默认的PropertyEditor,可以添加自定义的来覆盖它。在添加时可以使用一个自动检测的机制:也就是需要遵照一定的规则
具体的规则是:PropertyEditor类和标准的 JavaBeans在同一个包下,并且他们PropertyEditor的类名是JavaBeans的类名加上“Editor”,比如:
- public class ExoticTypeEditor extends PropertyEditorSupport {
- public void setAsText(String text) {
- setValue(new ExoticType(text.toUpperCase()));
- }
- }
可以看到这个PropertyEditor就是遵照了以上的命名规则,并且和ExoticType放在同一个包中,所以无需额外的配置就可以得到下面的输出:
ANAMEFOREXOTICTYPE
那么若没有符合以上规则的话,怎么办呢?可以通过org.springframework.beans.factory.config.CustomEditorConfigurer这个Bean来注册
为这个Bean配置customEditors属性,该属性是一个Map,将我们需要注册的PropertyEditors都注入到这个Map里就可以了:
- <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
- <property name="customEditors">
- <map>
- <entry key="document.six.test.ExoticType" value="document.six.test.ExoticType2Editor" />
- </map>
- </property>
- </bean>