Spring Bean加载过程

  Spring Bean的加载依赖于BeanFactory,但实际使用时不会直接使用BeanFactory,而是采用ApplicationContext这个在BeanFactory基础上提供了扩展的接口:

1
2
3
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, 
HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

  ApplicationContext接口具体的实现类常用的有:FileSystemXmlApplicationContet (从文件系统中读入Bean定义资源文件)、ClassPathXmlApplicationContext(从Classpath类路径中读入Bean定义资源文件)和XmlWebApplicationContext(从Web容器如Tomcat等中读入Bean定义资源文件)等。

  以FileSystemXmlApplicationContext为例,通过分析FileSystemXmlApplicationContext及其父类的源码来分析IoC容器定位Bean定义资源文件的实现过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {

public FileSystemXmlApplicationContext() {
}

public FileSystemXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
//configLocation是Bean定义资源文件路径
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}

public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}

public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
this(configLocations, true, parent);
}

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
this(configLocations, refresh, null);
}

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
//调用父类AbstractRefreshableConfigApplicationContext的方法,
//设置Bean定义的资源文件,完成IoC容器Bean定义资源的定位
setConfigLocations(configLocations);
if (refresh) {
//调用父类AbstractApplicationContext的refresh()
//函数启动载入Bean定义的过程,是Ioc容器载入Bean定义的入口
refresh();
}
}

@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}

  通过代码可以知道,在创建FileSystemXmlApplicationContext容器时,首先,调用父类容器的构造方法super(parent)方法为容器设置好Bean资源加载器。然后,再调用setConfigLocations(configLocations)方法设置Bean定义资源文件的定位路径。

  Spring IoC容器对Bean定义资源的载入是从refresh()函数开始的,FileSystemXmlApplicationContext通过调用其父类AbstractApplicationContextrefresh()函数开始整个IoC容器对Bean定义的载入过程。AbstractApplicationContext#refresh()载入Bean定义过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public void refresh() throws BeansException, IllegalStateException {  
synchronized (this.startupShutdownMonitor) {
prepareRefresh();

//创建bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

//为BeanFactory配置容器特性,例如类加载器、事件处理器等
prepareBeanFactory(beanFactory);
try {
//为容器的某些子类指定特殊的BeanPost事件处理器
postProcessBeanFactory(beanFactory);

//调用所有注册的BeanFactoryPostProcessor的Bean
invokeBeanFactoryPostProcessors(beanFactory);

//为BeanFactory注册BeanPost事件处理器.
//BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件
registerBeanPostProcessors(beanFactory);

//初始化信息源,和国际化相关.
initMessageSource();

//初始化容器事件传播器.
initApplicationEventMulticaster();

//调用子类的某些特殊Bean初始化方法
onRefresh();

//为事件传播器注册事件监听器.
registerListeners();

//初始化所有剩余的单态Bean.
finishBeanFactoryInitialization(beanFactory);

//初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
}
catch (BeansException ex) {
//销毁以创建的单态Bean
destroyBeans();
//取消refresh操作,重置容器的同步标识.
cancelRefresh(ex);
throw ex;
}
}
}

  refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以refresh()obtainFreshBeanFactory()是载入过程的开始:

1
2
3
4
5
6
7
8
9
10
   //AbstractApplicationContext.java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//这里是关键的 refreshBeanFactory 方法
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

  AbstractApplicationContextobtainFreshBeanFactory()方法调用refreshBeanFactory()方法,启动容器载入Bean定义资源文件的过程。AbstractApplicationContext类中只抽象定义了refreshBeanFactory()方法,容器真正调用的是其子类AbstractRefreshableApplicationContext#refreshBeanFactory(),方法的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected final void refreshBeanFactory() throws BeansException {  
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建IoC容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//对IoC容器进行定制化,如设置启动参数,开启注解的自动装配等
customizeBeanFactory(beanFactory);
//调用载入Bean定义的方法,具体的实现调用子类容器
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " +
getDisplayName(), ex);
}
}

  refreshBeanFactory()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入。
  createBeanFactory()是创建了DefaultListableBeanFactory工厂,载入BeanDefinition的方法loadBeanDefinitions只是AbstractRefreshableApplicationContext类中的抽象方法。
  AbstractRefreshableApplicationContext的子类有XmlWebApplicationContextAnnotationConfigWebApplicationContext。看类名就大概知道分别是解析哪种类型的配置。
  解析好的BeanDefinition,由 BeanDefinitionReaderUtils.registerBeanDefinition() 注册到DefaultListableBeanFactory中的beanDefinitionMap

1
2
3
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap =
new ConcurrentHashMap<String, BeanDefinition>(256);

  注意上里的BeanDefinition只是解析后的类Bean定义的相关数据,并没进行依赖注入,依赖注入在以下两种情况发生:

(1)用户第一次通过getBean方法向IoC容索要Bean时,IoC容器触发依赖注入。
(2)当用户在Bean定义资源中为<Bean>元素配置了lazy-init属性,即让容器在解析注册Bean定义时进行预实例化,触发依赖注入。


AbstractApplicationContext#refresh()方法中obtainFreshBeanFactory()执行完后所有的BeanDefinition已经初始化好了。之后会涉及到BeanFactoryPostProcessor、BeanPostProcessor的调用,先不细入分析代码,只是大概介绍一下调用的先后顺序:

​ 在上面的过程中,会调用beanFactory#getBean()来取得bean,来看下getBean()方法,我们知道BeanFactory接口中定义了几个getBean方法,就是向IoC容器索取管理的Bean的方法,在getBean时会完成对应bean的初始化。由于调用的层次比较复杂,最终调用了AbstractBeanFactory#getBean()方法,该方法实际上是调用了其AbstractBeanFactory#doGetBean()方法。

  在doGetBean()方法中,如果Bean定义的单态模式(Singleton),则容器在创建之前先从缓存中查找,以确保整个容器中只存在一个实例对象。如果Bean定义的是原型模式(Prototype),则容器每次都会创建一个新的实例对象。除此之外,Bean定义还可以扩展为指定其生命周期范围。具体的Bean实例对象的创建过程由createBean()方法完成,其具体的实现类是AbstractAutowireCapableBeanFactory,最终的bean的创建是AbstractAutowireCapableBeanFactory#doCreateBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {

// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
//......

// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
//......

return exposedObject;
}

  createBeanInstance()方法是根据XML的定义调用bean的有参或无参构造函数。跟踪该方法,我们最终会发现有个getInstantiationStrategy()方法,该方法的作用是获得实例化的策略对象,也就是指通过哪种方案进行实例化的过程,Spring当中提供了两种实例化方案:BeanUtils和CGLIB方式。BeanUtils实现机制是通过Java的反射机制,Cglib是一个第三方类库采用的是一种字节码加强方式机制。
  populateBean()方法会获得BeanDefinition中设置的property信息,对这些property进行赋值,即依赖注入的过程。在这个方法里完成对属性的注入,比如setXxx()方法的调用、属性的注解注入。

  对于initializeBean()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}

if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

  invokeAwareMethods()方法判断是BeanNameAware、BeanFactoryAware之类的Aware类型,如果是的话就执行对应方法。
  applyBeanPostProcessorsBeforeInitialization()方法是如果实现了BeanPostProcessor接口,这里会执行postProcessBeforeInitialization方法。
  invokeInitMethods()方法中,先判断是否实现了InitializingBean接口,如果是执行afterPropertiesSet()方法,然后如果配置了init-method就执行initMethod方法。
  applyBeanPostProcessorsAfterInitialization()方法是如果实现了BeanPostProcessor接口,这里会执行postProcessAfterInitialization方法。
  到此为止一个BeanFactoryPostProcessor的Bean就初始化完成了。

  于是就可以通过BeanFactoryPostProcessor的postProcessBeanFactory()的调用,来修改某些beanDefinition的值,示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);

System.out.println(bd.getBeanClassName());
PropertyValue[] pvArray = bd.getPropertyValues().getPropertyValues();
for (PropertyValue pv : pvArray) {
System.out.println(pv.getName() + "---" + pv.getValue());
}

ConstructorArgumentValues cas = bd.getConstructorArgumentValues();
for (ConstructorArgumentValues.ValueHolder valueHolder : cas.getIndexedArgumentValues().values()) {
System.out.println(valueHolder.getName() + "---" + valueHolder.getValue());
}

for (ConstructorArgumentValues.ValueHolder valueHolder : cas.getGenericArgumentValues()) {
System.out.println(valueHolder.getName() + "---" + valueHolder.getValue());
}
}
}

  Spring中的PropertyPlaceholderConfigurer正是通过这种方式来实现了配置宏替换。

  • 需要注意的是,BeanPostProcessor在源码注释已经表述了,只有当其它非实现BeanPostProcessor的bean且在同一个容器的bean在初始化的时候,才会回调BeanPostProcessor重写的那些方法,所以一个继承了BeanPostProcessor的类初始化会发现是不会有override方法的回调的。

  执行顺序:Constructor > @PostConstruct > InitializingBean > init-method,@PostConstruct优先于后者是因为CommonAnnotationBeanPostProcessor这个类,它继承自InitDestroyAnnotationBeanPostProcessor,用于处理@PostConstruct这类注解的BeanPostProcessor,所以先于InitializingBean执行。


转载自:
http://blog.csdn.net/chjttony/article/details/6248682
http://blog.csdn.net/chjttony/article/details/6263347
http://blog.csdn.net/chjttony/article/details/6278627