Spring的IoC容器所起的作用,就是生产bean,并维持bean间的依赖关系。它会以某种方式加载Configuration Metadata(通常也就是XML格式的配置信息),然后根据这些信息绑定整个系统的对象,最终组装成一个可用的基于轻量级容器的应用系统。 

IoC实现上面要求的过程,可以分解为两步:



启动阶段分析:

1 加装资源文件

2 通过工具类(BeanDefinitionReader),分析资源文件

3 生成对应的BeanDefinition

4 将BeanDefinition注册到BeanDefinitionRegistry。

实例化阶段分析:

显示地调用container.getBean会触发bean的实例化

当实例化A的时候发现A依赖B,那么就会触发B的实例化。





当实例化某个对象的时候,首先会检查对象是否已经初始化,如果没有的话,初始化。

如果有依赖的对象,就注入之。

如果对象实现了某些回调接口,就根据接口装备它。

插手容器的启动

Spring提供了一种叫做BeanFactoryPostProcessor的容器扩展机制。该机制允许我们在容器实例化相应对象之前,对注册到容器的BeanDefinition所保存的信息做相应的修改。这就相当于在容器实现的第一阶段最后加入一道工序,让我们对最终的BeanDefinition做一些额外的操作,比如修改其中bean定义的某些属性,为bean定义增加其他信息等。 

使用BeanFactoryPostProcessor的方式,就是实现这个接口,然后在实现类里写逻辑。

我们先看看这个接口

public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

上面的英文大家能看懂吧。allows for overriding or adding properties even to eager-initializing beans.

但是,因为Spring已经提供了几个现成的BeanFactoryPostProcessor实现类,所以,大多时候,我们很少自己去实现某个BeanFactoryPostProcessor。其中,org.springframework.beans. factory.config.PropertyPlaceholderConfigurer和org.springframework.beans.factory.config.Property OverrideConfigurer是两个比较常用的BeanFactoryPostProcessor。

PropertyPlaceholderConfigurer

通常情况下,我们不想将类似于系统管理相关的信息同业务对象相关的配置信息混杂到XML配置文件中,以免部署或者维护期间因为改动繁杂的XML配置文件而出现问题。我们会将一些数据库连接信息、邮件服务器等相关信息单独配置到一个properties文件中,这样,如果因系统资源变动的话,只需要关注这些简单properties配置文件即可。 

看例子:

容器使用BeanFactory

//声明将被后处理的BeanFactory实例
ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("..."));
//声明要使用的BeanFactoryPostProcessor
PropertyPlaceholderConfigurer propertyPostProcessor = new PropertyPlaceholderConfigurer();
propertyPostProcessor.setLocation(new ClassPathResource("..."));
//执行后处理操作
propertyPostProcessor.postProcessBeanFactory(beanFactory); 

使用Application

只需在xml文件中加上

...
<beans>
  <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
   <property name="locations">
   <list>
      <value>conf/myjdbc.properties</value>
      <value>conf/mail.properties</value>
     </list>
   </property>
  </bean>
   ...
</beans>  

使用了propertyPlaceHolderConfigure后,xml中dataSource如下

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="url">
   <value>${jdbc.url}</value>
  </property>
  <property name="driverClassName">
   <value>${jdbc.driver}</value>
  </property>
  <property name="username">
   <value>${jdbc.username}</value>
  </property>
  <property name="password">
   <value>${jdbc.password}</value>
  </property>
  <property name="testOnBorrow">
   <value>true</value>
  </property>
  <property name="testOnReturn">
   <value>true</value>
  </property>
  ...
</bean>    
##myjdbc.properties
jdbc.url=jdbc:mysql://server/MAIN?useUnicode=true&characterEncoding=ms932&failOverReadOnly=false&roundRobinLoadBalance=true
jdbc.driver=com.mysql.jdbc.Driver
jdbc.username=your username
jdbc.password=your password 

xml中的${jdbc.url},就用properties中的jdbc.url相对应。

没有什么好讲的,就是这些死内容而已。

PropertyOverrideConfigurer

PropertyOverrideConfigurer干的事,就是修改从xml(无论是否包含propertyPlaceHolderConfigure的properties)加载过来的信息。

下面是针对dataSource定义给出的PropertyOverrideConfigurer的propeties文件配置信息:

##文件名是adjusment.properties
dataSource.minEvictableIdleTimeMillis=1000
dataSource.maxActive=50 

注意这个dataSource指的是beanName。***

这样,当按照如下代码,将PropertyOverrideConfigurer加载到容器之后,dataSource原来定

义的默认值就会被pool-adjustment.properties文件中的信息所覆盖:

<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
  <property name="location" value="adjusment.properties"/>
< /bean> 

PropertyOverrideConfigurer使用BeanFactory的方式,我就不再赘述了。

说实话,我并不觉得PropertyOverrideConfigurer有什么卵用。

CustomEditorConfigurer

java是强类型的一种语言:int,String,String[],Person等等等等。

而我们配置的xml,里面都是字面量,也就是说,spring拿到的原始数据全部是字符串。

那么,spring是怎么把字符串转成各种各样的类型呢?

用工具呗?

用什么工具?

CustomEditorConfigurer

Spring内部通过JavaBean的PropertyEditor来帮助进行String类型到其他类型的转换工作。只要为每种对象类型提供一个PropertyEditor,就可以根据该对象类型取得与其相对应的PropertyEditor来做具体的类型转换。Spring容器内部在做具体的类型转换的时候,会采用JavaBean框架内默认的PropertyEditor搜寻逻辑。

同时,Spring框架还提供了自身实现的一些Property-Editor。

  StringArrayPropertyEditor。该PropertyEditor会将符合CSV格式的字符串转换成String[]数组的形式,默认是以逗号(,)分隔的字符串,但可以指定自定义的字符串分隔

符。ByteArrayPropertyEditor、CharArrayPropertyEditor等都属于类似功能的Property- Editor,参照Javadoc可以取得相应的详细信息。 

  ClassEditor。根据String类型的class名称,直接将其转换成相应的Class对象,相当于通过Class.forName(String)完成的功效。可以通过String[]数组的形式传入需转换的值,以达到与提供的ClassArrayEditor同样的目的。 

  FileEditor。Spring提供的对应java.io.File类型的PropertyEditor。同属于对资源进行定位的PropertyEditor还有InputStreamEditor、URLEditor等。 

  LocaleEditor。针对java.util.Locale类型的PropertyEditor,格式可以参照Local-eEditor和Locale的Javadoc说明。 

  PatternEditor。针对JavaSE1.4之后才引入的java.util.regex.Pattern的Property-Editor,格式可以参照java.util.regex.Pattern类的Javadoc。

更多的关于CustomEditorConfigurer的资料参考 http://blog.csdn.net/zhoudaxia/article/details/36247883#t4

注意

按照JavaBeans的规范,JavaBeans的基础设施会在JavaBean相同类包下查找是否存在<JavaBean>Editor的类,如果存在,自动使用<JavaBean>Editor作为该JavaBean的PropertyEditor。

  如com.baobaotao.domain.UserEditor会自动成为com.baobaotao.domain.User对应的PropertyEditor。Spring也支持这个规范,也即如果采用这种规约命令PropertyEditor,就无须显式在CustomEditorConfigurer中注册了,Spring将自动查找并注册这个PropertyEditor。(甚至不用在xml中使用bean这个标签声明一个UserEditor)







如果是使用的是BeanFactory的实现,如XmlBeanFactory,就得通过硬编码的方式来应用CustomEditorConfigurer到容器中了。

XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource
CustomEditorConfigurer ceConfigurer = new CustomEditorConfigurer();
Map customerEditors = new HashMap();
customerEditors.put(java.util.Date.class, new DatePropertyEditor()); //以后凡是string转Date型的 都用DatePropertyEditor
ceConfigurer.setCustomEditors(customerEditors);
ceConfigurer.postProcessBeanFactory(beanFactory);   

DatePropertyEditor如下

如果我们想把某种格式的字符串转化为Person类,那么我们可以采用上面的方式,但是如果我们想把spring转化成date,我们又不能新建一个package名字叫java.util。

所以我们得让容器知道CustomEditorConfigurer的实现。

使用硬编码的方式,上面已经说了

如果是采用ApplicationContext,xml如下:

使用时:

大家注意,我给DateFoo传递的事一个"符合"DatePropertyEdit中datePattern格式的字符串"2007/10/16",这个字符串就是DatePropertyEdit中setAsTest方法中的参数

通过CustomerEditorConifgure,Spring已经知道了凡是String要转化成Date都去找datePropertyEdit... 后面的大家应该都能看懂了

不过在spring2.0之后,提倡使用,比较提倡使用propertyEditorRegistrars属性来指定自定义的PropertyEditor。这样一来我们就多了一步,实现PropertyEditorRegistrar 接口

然后在xml里这样注册:

再次注意:

我们知道有了上面的配置后,string转成date就会用datePrpertyEditor这个类

但是,这个类是什么时候被调用的呢?

答案是: 在getBean的时候

感谢glt

参考资料

http://blog.csdn.net/zhoudaxia/article/details/36247883

Spring揭秘 读书笔记 五 容器的启动的更多相关文章

  1. Spring揭秘 读书笔记 七 BeanFactory的启动分析

    首先,先看我自己画的BeanFactory启动时的时序图. 第一次接触时序图,可能有些地方画的不是很符合时序图的规则,大家只关注调用顺序即可. public static void main(Stri ...

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

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Pr ...

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

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...

  4. Spring揭秘 读书笔记 三 bean的scope与FactoryBean

    本书可作为王富强所著<<Spring揭秘>>一书的读书笔记  第四章 BeanFactory的xml之旅 bean的scope scope有时被翻译为"作用域&quo ...

  5. spring揭秘 读书笔记 一 IoC初探

    本文是王福强所著<<spring揭秘>>一书的读书笔记 ioc的基本概念 一个例子 我们看下面这个类,getAndPersistNews方法干了四件事 1 通过newsList ...

  6. Spring揭秘读书笔记 八 数据访问异常体系

    这篇博客 来自spring揭秘一书的第十三章 为什么要有访问异常都有一个体系,这个我们得从DAO模式说起. DAO模式 任何一个系统,不管是一个最简单的小系统,还是大规模的系统,都得跟数据打交道,说白 ...

  7. spring揭秘 读书笔记 六 bean的一生

    我们知道,Spring容器具有对象的BeanDefinition来保存该对象实例化时需要的数据. 对象通过container.getBean()方法是才会初始化该对象. BeanFactory 我们知 ...

  8. Spring揭秘 读书笔记 四----方法注入

    我们知道,拥有prototype类型scope的bean,在请求方每次向容器请求该类型对象的时候,容器都会返回一个全新的该对象实例. 我们看下面的例子: public class MockNewsPe ...

  9. spring揭秘读书笔记----spring的ioc容器之BeanFactory

    spring的ioc容器是一种特殊的Ioc Service Provider(ioc服务提供者),如果把普通的ioc容器认为是工厂模式(其实很相似),那spring的ioc容器只是让这个工厂的功能更强 ...

随机推荐

  1. iOS不能交互的几种情况

    alpha <=0.01 hidden = YES userInteraction = NO 父试图不允许交互,子试图也不允许交互: 在父试图可见范围内,可以交互,超出部分失效,不能交互

  2. JavaScript Window Navigator

    window.navigator 对象包含有关访问者浏览器的信息. Window Navigator window.navigator 对象在编写时可不使用 window 这个前缀. 实例 <d ...

  3. Java内存泄漏分析系列之二:jstack生成的Thread Dump日志结构解析

    原文地址:http://www.javatang.com 一个典型的thread dump文件主要由一下几个部分组成: 上图将JVM上的线程堆栈信息和线程信息做了详细的拆解. 第一部分:Full th ...

  4. 分布式服务框架Dubbo

    随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用架构 当网站流量很小时,只需一个应用, ...

  5. 安卓高级3 Android应用Design Support Library完全使用实例

    原作者:http://www.open-open.com/lib/view/open1433385856119.html 1 背景 上周一年一度的Google IO全球开发者大会刚刚结束,Google ...

  6. Programming In Scala笔记-第八章、函数与闭包

    当程序的代码量增大时,就需要对各功能模块进行分割,这些分割的小模块就是本文中接下来会进行分析的函数.接下来的部分会讲解包括函数嵌套,函数字面量,以及函数值等概念. 一.方法 一会函数一会方法的,是不是 ...

  7. 24 服务AIDL

    AIDL远程访问服务的方法 创建一个接口类写上方法 然后修改后缀java为aidl 在服务中创建一个类继承Stub类 在远程访问服务的进程把AIDL文件复制(包名不能改变) XXXX.Stub.asI ...

  8. Win7下安装linux虚拟机

    关于如何在Win7下搭建linux学习环境,特在此分享下. 一.工具 1.VMware-workstation-full-9.0.0-812388.exe       下载地址:http://pan. ...

  9. ScrollView的阻尼回弹效果实现(仿qq空间)

    玩过新浪微博,qq空间等手机客户端的童鞋,都应该清楚,在主界面向下滑动时,会有一个阻尼回弹效果,看起来挺不错,接下来我们就来实现一下这种效果,下拉后回弹刷新界面,先看效果图: 这个是编辑器里面的界面效 ...

  10. python学习资料整理

    [1] The Python Tutorial [2] Numpy Quick Start Tutorial [3] Python-OpenCV [4] http://www.learnpython. ...