1. PropertyPlaceholderConfigurer 和PropertyOverrideConfigurer
1.1 类的功能
PropertyPlaceholderConfigurer这个类是用于将外部指定properties文件中的变量值替换到配置文件中属性定义的占位符中。PropertyOverrideConfigurer与PropertyPlaceholderConfigurer类似,该类将会用外部properties文件中的属性的值替换spring容器中指定bean中的指定属性的值。因此PropertyOverrideConfigurer的需要的properties文件格式必须按照以下格式:
beanName.propertyName=propertyValue
它与PropertyPlaceholderConfigurer的区别在于:
a. 不是通过占位符来进行匹配。
b. bean的property可以出现在配置之中也可以不出现。
1.2 类结构
在分析具体实现之前,先看类结构图:
1.2.1 PropertiesLoaderSupport:
该类用于对properties进行加载,它支持两种方式指定properties:一种是通过properties属性在配置文件中通过<props></props>元素指定,这种方式称为local方式
一种是通过locations属性从外部properties或者xml文件中读取。
当然这两种方式可以同时存在,当出现同名冲突时,可以通过localOverride参数来指定那种方式中的同名配置起作用,false时,优先使用外部文件中的配置,true则相反,默认为false。
properties文件加载,PropertiesLoaderSupport会委托给DefaultPropertiesPersister来进行。
1.2.2 PropertyResourceConfigurer:
该类实现了PriorityOrdered和BeanFactoryPostProccessor接口,同时抽取了在属性置换或者占位符处理之前的共同逻辑,包括:1.加载properties,并合并同名配置。
2.对properties的value进行转换,这里暴露了一个convertProperties()方法,便于子类扩展,子类可以通过覆盖该方法来进行一些特殊操作,譬如加密解密等。
3.提供processProperties()抽象接口用于子类扩展。
由于它实现了BeanFactoryPostProccessor接口,因此,可以知道它的执行时机是在beanFacotry创建完毕,且BeanDefinition加载完成之后就会执行。具体的位置在AbstractApplicationContext.refresh()->AbstarctApplicationContext.invokeBeanFactoryPostProcessors()中
1.2.3 PropertyPlaceholderConfigurer:
该类利用properties中指定的value替换占位符的内容。通过分析可以知道,该类除了能够支持PropertiesLoaderSupport的两种方式加载properties外,还可以支持从JVM运行参数中加载properties.当然,对于名字冲突重名的情况,它提供了参数供选择:
SYSTEM_PROPERTIES_MODE_NEVER:不从System.getProperties中加载
SYSTEM_PROPERTIES_MODE_FALLBACK:若在前两种方式都无法解析的占位符,则尝试从System.getProperties()中加载。该参数下,System.getProperties()优先级最低。默认值为该值。
SYSTEM_PROPERTIES_MODE_OVERRIDE:优先从System.getProperties()中加载属性值。
另外,在spring 2.5版之后,对于占位符出现的位置可以是下面几处
<bean id="test" class="${beanClass}" parent="${parentName}" scope="${scope}" factory-bean="${factoryBeanName}" factory-method="${factoryMethod}">
<constructor-arg index="0"><value>${constructorValue}</value></constructor-arg>
<property name="p1">
<value>${propertyValue}</value>
</property>
</bean>
1.2.4 PropertyOverrideConfigurer
该类直接用指定properties中的值替换掉bean中属性值,它要求属性配置文件中的格式必须满足beanName.propertyName=propertyValue
因此,它不需要像PropertyPlaceholderConfigurer一样显式指定占位符。它的处理逻辑也很简单,通过properties中指定的配置获取配置相对应的beanName,然后从beanFactory中得到BeanDefinition,然后用propertyValue替换名为propertyName的属性。
2 CustomEditorConfigurer
该类用于支持用户向beanFacotry中注册一些自定义的复杂类型转换器,用于将字符串转换为一些特殊类型的值。2.1 类结构图:
类图中PropertyEditor是java.beans中定义的属性编辑器的通用接口。PropertyEditorSupport实现了该接口,并实现了一部分通用对逻辑。
PropertyEditorRegistrar定义了一个属性注册器(PropertyEditorRegistry)的管理器接口。用于管理多个PropertyEditorRegistry
PropertyEditorRegistry定义了一个属性注册器接口,用于管理多个PropertyEditor。
2.2 两种注册方式
CustomEditorConfigurer支持两种方式的自定义属性编辑器的注册。一种是向CustomEditorConfigurer注册多个属性注册器管理器,当在不同情况下(如编写一个相应的注册器然后在多种情况下重用它)需要使用相同的属性编辑器时该接口特别有用。如:
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="mypackage.MyCustomDateEditorRegistrar"/>
<bean class="mypackage.MyObjectEditorRegistrar"/>
</list>
</property>
</bean>
另一种是直接向CustomEditorConfigurer添加多个属性编辑器PropertyEditor,如:
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" value="mypackage.MyCustomDateEditor"/>
<entry key="mypackage.MyObject" value="mypackage.MyObjectEditor"/>
</map>
</property>
</bean>
需要注意的是,<entry>个格式必须满足key为转换的目标对象的class名,value是属性编辑器的类名(当然也支持编辑器的实例,但是高版本的spring已经不建议这么做)
由类结构图可以看出CustomEditorConfigurer实现了BeanFactoryPostProcessor,因此它的执行时机也是在beanFacotry创建完毕,且BeanDefinition加载完成之后就会执行。由于通过Ordered接口指定了LOWEST_PRECEDENCE,即最低级别的Order,它的执行顺序会相对靠后。
2.3 何时使用自定义PropertyEditor?
spring在创建bean实例过程中。具体讲来就是在创建BeanWrapperImpl实例后,spring会复制一份当前容器中注册的PropertyEditor到BeanWrapperImpl中,用于属性转换,具体请参考 spring bean实例化过程