在前面 Spring Bean加载过程(一) 文章中,分析了在refresh()
方法中obtainFreshBeanFactory()
执行完后所有的BeanDefinition已经初始化好了。之后会调用下面的代码:
//为容器的某些子类指定特殊的BeanPost事件处理器
postProcessBeanFactory(beanFactory);
//调用所有注册的BeanFactoryPostProcessor的Bean
invokeBeanFactoryPostProcessors(beanFactory);
//为BeanFactory注册BeanPost事件处理器.
//BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件
registerBeanPostProcessors(beanFactory);
//初始化信息源,和国际化相关.
initMessageSource();
//初始化容器事件传播器.
initApplicationEventMulticaster();
//调用子类的某些特殊Bean初始化方法
onRefresh();
//为事件传播器注册事件监听器.
registerListeners();
//初始化所有剩余的单态Bean.
finishBeanFactoryInitialization(beanFactory);
//初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
这里会涉及到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
:
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()
方法:
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的值,示例:
@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执行。