《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

时间: 2025-01-01 08:57:58

《Spring揭秘》——IOC梳理2(容器启动)的相关文章

Spring源码分析2 — 容器启动流程

1 主要类 部署web应用时,web容器(比如Tomcat)会读取配置在web.xml中的监听器,从而启动spring容器.有了spring容器之后,我们才能使用spring的IOC AOP等特性.弄清spring容器启动流程,有利于理解spring IOC中的各种特性,比如BeanPostProcessor,MessageSource,ApplicationListener等.我们先来看下容器启动流程中涉及的主要类. ContextLoaderListener:注册在web.xml中,web应

spring源码:web容器启动(li)

web项目中可以集成spring的ApplicationContext进行bean的管理,这样使用起来bean更加便捷,能够利用到很多spring的特性.我们比较常用的web容器有jetty,tomcat,jboss等,以jetty为例,我们看一下web容器是如何初始化和启动spring的context. 一.Spring容器的加载 在web工程中都有一个web.xml文件,jetty在启动的时候会加载这个配置文件,并且对文件中的各个listener进行加载.ContextLoaderListe

《Spring揭秘》(八)---- IoC容器及Bean的生命周期

Spring的IoC容器会以某种方式加载配置信息,然后根据这些信息绑定整个系统的对象,最终组装成一个可用的基于轻量级容器的应用系统.实现以上功能,分为两个阶段:容器启动阶段和Bean实例化阶段.而且Spring的IoC容器在每个阶段都加入了相应的扩展点,以便根据具体场景的需要加入自定义的扩展逻辑. 1 容器启动阶段 首先会通过某种途径加载配置信息,大部分情况下,容器需要依赖某些工具类(BeanDefinitionReader)对加载的配置信息进行解析和分析,并将分析后的信息编组为相应的BeanD

《Spring揭秘》——IOC梳理1

依赖注入的三种方式: 1.构造方法注入:对象构造完成后,即进入就绪状态,可以马上使用.缺点是有时候构造方法的参数列表较长,构造方法无法被继承,无法设置默认值. 2.setter方法注入:相对宽松,可在对象构造完成后再注入.setter方法可以被继承,允许设置默认值.缺点是无法在构造完成后就进入就绪状态. 3.接口注入:类需要实现某个接口,接口定义了注入方法,方法的参数即为所依赖对象的类型.(不推荐,较为死板和烦琐.) IoC Service Provider的职责: 业务对象的构建管理:业务对象

Spring 源码学习(二) IOC容器启动过程

这一节主要是记录一下Spring Ioc 容器的启动过程. Spring 的 Ioc 容器是怎么被加载和使用的? web容器为它提供了宿主环境 ServlectContext,  Tomcat 启动时会读取web.xml. 并且实例化web.xml中配置的ContextLoaderListener ,下面看一下ContextLoaderListener的创建过程: 在实例化ContextLoaderListener 之后,通过接口回调执行ContextLoaderListener 类中的cont

深入理解Spring的IOC容器

IOC概述 IOC是Spring容器的内核,AOP.声明式事务等功能都依赖于此功能,它涉及代码解耦.设计模式.代码优化等问题的考量,我们将通过以下三个方面来深入理解IOC: IoC的初步理解 IoC的注入类型 构造器注入:通过调用类的构造函数,将接口实现的类通过构造函数变量传入. 属性注入:通过setter方法完成调用类所需依赖的注入,更加灵活方便. 接口注入:将调用类所有依赖注入的方法抽取到一个接口中,调用类通过实现该接口提供相应的注入方法. IoC的注入方式 Spring最为一个容器,通过配

好莱坞原则—Spring的IOC容器

IOC容器的概念,之前在学习SSH的时候,就有接触过.但那时候也仅仅是知道这么个概念,认为它非常难理解.事实上并非它难理解,而是我并没有停下来好好对它总结梳理过. IOC(Inversion of Control)简单介绍: 控制反转",并非一种技术.而是一种思想.一种主动提供服务的思想.所谓IOC,就是由Spring负责控制对象的生命周期和对象间的关系,与我们传统的在对象内部直接控制背道而驰. 在传统的程序开发中,完毕一个业务逻辑至少须要两个或两个以上的对象协助完毕.通常一个对象要使用另外一个

Spring的IOC容器—scope作用域

Scope 简介: Scope用来声明容器中的对象的存货时间.即容器在对象在进入其相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁这些对象. Sprign容器最初提供了两种bean的scope类型:singletoon和prototype.自Spring2.0之后,引入了另外三种scope类型,即request.session和global session类型.这三种类型只能再web中使用. 1.Singleton 代表在Spring的IOC容器

Spring核心技术IoC容器(六)

前文已经描述了Bean的作用域,本文将描述Bean的一些生命周期作用,配置还有Bean的继承. 定制Bean 生命周期回调 开发者通过实现Spring的InitializeingBean和DisposableBean接口,就可以让容器来管理Bean的生命周期.容器会调用afterPropertiesSet()前和destroy()后才会允许Bean在初始化和销毁Bean的时候执行一些操作. JSR-250的@PostConstruct和@PreDestroy注解就是现代Spring应用生命周期回