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. 网络流24题第一题(luogu2796飞行员配对方案)

    飞行员配对方案 二分图裸题,可以拿最大流怼. 题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 ...

  2. 初步配置阿里云ECS服务器

    阿里云服务器配置记录01 购买阿里云学生服务器9.9元每月 创建ubuntu64位实例系统,注意必须添加安全组设置才可远程登入(设置课访问端口及IP范围 putty 软件在windows10下远程登入 ...

  3. 建立自己的git服务器

    需求情景 就像金山快盘同步盘那样, 在开发环境windows 10和部署环境Ubuntu server 14.04之间建立同步关系.比如windows端多了一个a.txt文件,你推送后,Ubuntu端 ...

  4. Redis源码学习:Lua脚本

    Redis源码学习:Lua脚本 1.Sublime Text配置 我是在Win7下,用Sublime Text + Cygwin开发的,配置方法请参考<Sublime Text 3下C/C++开 ...

  5. Mongo 整体架构介绍(1)-------分片集群

    摘要 在mongo初识文中介绍了mongo与cassandra的主要区别,以及mongo物理部署架构图.本文接着上一篇的mongo 架构图,来继续讲分片集群. 分片介绍 shard key mongo ...

  6. MySQL执行插入操作时报错1366 - Incorrect string value

    今天在测试mysql时,发现插入数据的问题,下面和大家分享下解决方法: 首先看问题原因: [Err] 1366 - Incorrect string value: '\xCF\xD6' for col ...

  7. 详解EBS接口开发之库存事务处理-物料批次导入

    库存事务处理-物料批次导入 --系统批次表 SELECT * FROM MTL_LOT_NUMBERS T; --API创建批次 inv_lot_api_pub.create_inv_lot(x_re ...

  8. @property的参数

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51353580 本文出自:[openXu的博客] 参数类别 参数 说明 原子性 atomic ...

  9. Pycharm中进行Python远程开发

    http://blog.csdn.net/pipisorry/article/details/52269952 PyCharm提供两种远程调试(Remote Debugging)的方式:    配置远 ...

  10. 在Linux上的虚拟机上启动Oracle上报ORA-00845: MEMORY_TARGET not supported on this system的问题解决

    解决办法: 1.将当前虚拟机的内容调整大一些(以下转载:http://jingyan.baidu.com/article/414eccf67b8baa6b421f0a60.html) VMware虚拟 ...