Spring IoC 学习(2)
前言
知道了IoC的好处和优势之后,本来应该有的一步是,搞清楚怎么用。因为前面我写的顺序是:是什么,为什么?下一个part肯定的就是怎么办或者怎么用?但是,按照Spring的官方的Guide,我觉得应该大家是可以写个Hello World。网上这类的教程也很多,加上其实我这次学习Spring是想更加深入的学习,因此,重点就不放在这个部分了。主要放在学习背后的故事。
这小节的内容就是学习IoC的容器。
两种容器
概述
整个IoC容器可以分为两个阶段,容器启动阶段和实例化阶段。
容器启动阶段
①就是把xml文件里面的配置信息弄到BeanDefinition中。那就必须来看一下BeanDefinition
private volatile Object beanClass;
private String scope;
private boolean abstractFlag;
private boolean lazyInit;
private int autowireMode;
private int dependencyCheck;
private String[] dependsOn;
...
这个里面的东西也是相当的多,但是总的来说就是记录一些bean的信息,方便与后面的实例化。
② 读完配置文件之后,是得到了很多BeanDefinition。然后通过BeanDefinitionRegistry将这些bean注册到beanFactory中。下面看一看具体的实现类DefaultListableBeanFactory里面是如何注册的。
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap
= new ConcurrentHashMap<String, BeanDefinition>(64);
//... codes ...
//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//---------------------------------------------------------------------
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// ...codes...
this.beanDefinitionMap.put(beanName, beanDefinition);
// ...codes...
上面的代码虽然省略了很多很多的逻辑,但是实际重要的部分是我体现的那部分,首先,DefaultListableBeanFactory中先是new了一个final的ConcurrentHashMap,用来装BeanDefinition,然后经过一系列的逻辑判断之后,装进去。后面如果要拿出来,想着应该也是用相应的方法拿出来。
不信你看
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("No bean named '" + beanName + "' found in " + this);
}
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
到了这一步,按理,我们的第一步,即容器启动阶段就结束了。然而
Spring还给我们提供了接口,干什么呢?如果你想搞些事情呢?那我不能让你搞,岂不是很不好。开源框架嘛,拓展性非常重要。
接口--BeanFactoryPostProcessor就是做这个工作的,其中有几个Spring自带的,挺有用的BeanFactoryPostProcessor。
① PropertyPlaceHolderConfigurer
从这个类图上就可以看到,PropertyPlaceholderConfigurer间接实现了BeanFactoryPostprocessor。是Spring自带的搞事情实现类。
【主要功能】
为什么叫PropertyPlaceHolderConfigurer,PlaceHolder就叫做占位符,所以这个Configurer主要的功能特点,就是占位符相关的。例如,以下我们这种常见的应用。
很常见吧,我们不直接写值,而是写占位符,然后在其他地方我们再去写值。当然,要用它,必须要把它加上
② PropertyOverrideConfigurer
以下代码说明应用
<bean class ="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="properties">
<map>
<!-- 不管原来的sex是什么,最后就是male -->
<entry key="testBean.sex" value="male"/>
</map>
</property>
可以用来覆盖原来初始化的值。不过其实我有一个问题,为什么要多此一举。要不就是只有一种可能,那个配置文件,我们没法改,那我们就在这个地方做一个修改。这么想想的话,还是有些作用的。
③ CustomEditorConfigurer
这家伙的中文名叫自定义属性编辑器,又一个中文字面全看懂,不知道干啥用的典例。
Class Person{
Date birthday;
// setter getter 等默认有【懒】
}
beans.xml
<!-- 实例化直接是个String,人家怎么知道你是不是Date,怎么知道怎么转换 -->
<bean >
<property name="birthday">
<value>2017-08-29</value>
</property>
</bean>
<!-- 定义属性编辑器 -->
<bean >
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean >
<property name="format" value="yyyy-MM-dd"/>
</bean>
</entry>
</map>
</property>
</bean>
自己定义的日期类型编辑器
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* java.util.Date属性编辑器
* @author Administrator
*
*/
public class UtilDatePropertyEditor extends PropertyEditorSupport {
private String format="yyyy-MM-dd";
@Override
public void setAsText(String text) throws IllegalArgumentException {
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
Date d = sdf.parse(text);
this.setValue(d);
} catch (ParseException e) {
e.printStackTrace();
}
}
public void setFormat(String format) {
this.format = format;
}
}
Bean实例化阶段
本来是要把Bean实例化阶段也写完的,但是鉴于现在为止,整个的篇幅已经比较长,再写下去,怕是有人要烦了。【我才不会说是我累了】
最后更新:2017-08-29 18:03:18