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. Python-Jupyter Notebook使用技巧

    0. 体验与安装 首先可以通过Jupyter Notebook体验这个链接体验一下Jupyter Notebook. 首先安装ipython:pip3 install ipython 然后安装Jupy ...

  2. 使用Spring Boot开发Web项目

    前面两篇博客中我们简单介绍了Spring Boot项目的创建.并且也带小伙伴们来DIY了一个Spring Boot自动配置功能,那么这些东西说到底最终还是要回归到Web上才能体现出它的更大的价值,so ...

  3. Java集合框架总结

    java集合框架主要分为实现了Collection接口的List和Set.映射接口Map. |-- List 有序,元素都有索引,可重复. |-- Set 无序,不可以存储重复的元素. |-- Map ...

  4. 让你的代码减少三倍!使用kotlin开发Android(五) 监听器

    本文同步自 博主的私人博客wing的地方酒馆 在前面的博客中,有一个栗子,是点击按钮转跳的监听器. button.setOnClickListener { val user = User(" ...

  5. iOS图形手势识别框架SGGestureRecognizer

    简介 苹果官方为我们提供了简单手势的识别器,但对于图形手势,例如五角星.三角形等的识别,就需要自己实现了.通过识别这些手势,可以去执行特定的操作,或是输入公式.释放魔法等,可以为App增光添彩. 下载 ...

  6. 【SSH系列】深入浅出SpringMvc+入门Demo

    Spring MVC框架是有一个MVC框架,通过实现Model-View-Controller模式来很好地将数据.业务与展现进行分离.从这样一个角度来说,Spring MVC和Struts.Strut ...

  7. [OpenCV] 编译源程序 2.4.10 以支持 CUDA

    对源代码进行如下修改: H:\Software\opencv\sources\modules\gpu\src\nvidia\core\NCV.cu中添加 #include <algorithm& ...

  8. pandas小记:pandas数据输入输出

    http://blog.csdn.net/pipisorry/article/details/52208727 数据输入输出 数据pickling pandas数据pickling比保存和读取csv文 ...

  9. 安卓开发过程中空指针的问题Java.lang.NullPointerException

    最近做一个新闻客户端的应用,经常出现空指针的问题,我想一方面可能是自己水平有限,二是开发过程中有一些遗漏的地方.一般情况下新手出现空指针的概率较高.下面来总结一下经常出现的问题. 1.所谓的指针,就是 ...

  10. Java中for_each循环的使用

    最近在看一些和安卓相关的书籍,看到了for_each这种循环结构,这是为了简化java的for循环而改造的一种方便使用的格式. 格式如下: for(数据类型 变量:集合) 语句块 接下来看一个例程: ...