《Spring揭秘》——IOC梳理2(容器启动)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Spring揭秘》——IOC梳理2(容器启动)相关的知识,希望对你有一定的参考价值。
IoC容器背后的秘密
主要分为两个阶段:容器启动阶段、Bean实例化阶段。
容器启动阶段:
容器需要依赖某些工具类(BeanDefinitionReader)对加载的Configuration MetaData( 通常也就是XML格式的配置信息)。进行解析和分析,并将分析后的信息编组为相应的BeanDefinition,最后把这些保存了bean定义必要信息的BeanDefinition,注册到相应的BeanDefinitionRegistry,这样容器启动工作就完成了。
Bean实例化阶段:
该阶段,容器会首先检查所请求的对象之前是否已经初始化。如果没有,则会根据注册的BeanDefinition所提供的信息实例化被请求对象,并为其注入依赖。
插手“容器的启动”
Spring提供了BeanFactoryPostProcessor的容器扩展机制,允许我们在容器实例化相应对象之前,对注册到容器的BeanDefinition所保存的信息做相应的修改。相当于在容器实现的第一阶段最后加入一道工序,对最终的BeanDefinition做一些额外的操作,比如修改其中bean定义的某些属性,为bean定义增加其他信息等。一般情况下我们不会直接写该接口的实现类,而是使用Spring提供的相关类:PropertyPlaceholderConfigurer 、PropertyOverrideConfigurer、CustomEditorConfigurer。
1. PropertyPlaceholderConfigurer
PropertyPlaceholderConfigurer允许我们在XML配置文件中使用占位符(PlaceHolder),并将这些占位符所代表的资源单独配置到简单的properties文件中来加载。
<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>
或者<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${jdbc.user}"></property> ... </bean>
2. PropertyOverrideConfigurer
通过PropertyOverrideConfigurer对容器中配置的任何你想处理的bean定义的property信息进行覆盖替换。详情见P69。
配置在properties文件中的信息通常都以明文表示,PropertyOverrideConfigurer的父类PropertyResourceConfigurer 提供了一个protected类型的方法convertPropertyValue,允许子类覆盖这个方法对相应的配置项进行转换,如对加密后的字符串解密之后再覆盖到相应的bean定义中。当然,既然PropertyPlaceholderConfigurer也同样继承了PropertyResourceConfigurer,我们也可以针对PropertyPlaceholderConfigurer应用类似的功能。
(还是偏向于使用PropertyPlaceholderConfigurer,对配置文件中如用户名及密码加密了,想要解密即可使用PropertyPlaceholderConfigurer。)
public class EncryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer { private String[] encryptPropNames ={"jdbc.user","jdbc.password"}; @Override protected String convertProperty(String propertyName, String propertyValue) { if(isEncryptProp(propertyName)){ String decryptValue = DESUtils.getDecryptString(propertyValue); return decryptValue; }else{ return propertyValue; } } /** * 判断是否是加密的属性 */ private boolean isEncryptProp(String propertyName){ for(String encryptPropName:encryptPropNames){ if(encryptPropName.equals(propertyName)){ return true; } } return false; } }
在applicationContext.xml中需要进行如下配置:
<bean class="com.echo.utils.EncryptPropertyPlaceholderConfigurer" p:location="classpath:db.properties" p:fileEncoding="utf-8"></bean>
3.CustomEditorConfigurer
上面两个都是通过对BeanDefinition中的数据进行变更以达到某中目的,CustomEditorConfigurer只是辅助性地将后期会用到的信息注册到容器,对BeanDefinition没有做任何变动。实际应用时,主要是将XML中String字符串转化为对象类型。具体参照P72。
public class DatePropertyEditor extends PropertyEditorSupport { private String datePattern; @Override public void setAsText(String text) throws IllegalArgumentException { DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(getDatePattern()); Date dateValue = dateTimeFormatter.parseDateTime(text).toDate(); setValue(dateValue); } public String getDatePattern(){ return datePattern; } public void setDatePattern(String datePattern) { this.datePattern = datePattern; } }
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="java.util.Date"> <ref bean="datePropertyEditor"/> </entry> </map> </property> </bean> <bean id="datePropertyEditor" class="...DatePropertyEditor"> <property name="datePattern"> <value>yyyy/MM/dd</value> </property> </bean>
Spring 2.0之后,比较提倡使用propertyEditorRegistrars属性来指定自定义的PropertyEditor。(P72)
可参照http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/CustomEditorConfigurer.html
以上是关于《Spring揭秘》——IOC梳理2(容器启动)的主要内容,如果未能解决你的问题,请参考以下文章
sping揭秘4某些无法注册到IOC容器的对象如何交给spring托管