《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(容器启动)的主要内容,如果未能解决你的问题,请参考以下文章

《Spring揭秘》——IOC梳理1

《Spring揭秘》——IOC梳理3(资源加载,国际化)

《Spring揭秘》记录

sping揭秘4某些无法注册到IOC容器的对象如何交给spring托管

spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定

Spring之IOC容器初始化过程