Bean加载时机
Spring 容器内的Bean是在什么时候加载的呢?在Spring内有一个配置可以管控Bean加载的时机,即Lazy-Init,在绝大多数情况下,通常这个配置是false。把懒加载置为false的原因,是希望在Spring Ioc容器初始化的时候,就把所有的Bean都给初始化好。这样可以缩短系统接口的RT。对lazy-init属性的处理,实际的处理是在DefaultListableBeanFactory这个基本容器preInstantiateSingletons方法中完成的。
DefaultListableBeanFactory类内preInstantiateSingletons方法:
调用时机:AbstactApplicationContext refresh方法内的finishBeanFactoryInitialization(beanFactory);方法,具体逻辑:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
return getEnvironment().resolvePlaceholders(strVal);
}
});
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
其中会执行beanFactory.preInstantiateSingletons(), 此方法会初始化所有的单例的lazy-init=false的bean,即调用上面截图的方法。就会调用getBean方法,getBean方法是非常核心的一个方法,其中流程比较复杂。下面剖析下getbean的执行流程。
getBean执行流程
以上是getBean大体的执行流程,实际流程要比此复杂的多,其实从大的维度来看,getBean是分成了两大部分,其一是构造Bean对象,对bean进行实例化,其二是填充bean依赖的属性,其三是初始化。
1.对bean进行实例化的具体流程:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
最核心的逻辑:createBeanInstance,其核心代码如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Need to determine the constructor...
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
1.Class<?> beanClass = resolveBeanClass(mbd, beanName); 判断bean的是否能够可以实例化,如果没有public修饰符则会抛出异常,创建bean失败。
2.如果bean定义的工厂方法不为空,则调用工厂方法进行实例化。
3.resolved是true,autowireNecessary是true,则直接调用autowireConstructor进行实例化,否则则执行instantiateBean方法,这里的逻辑没有太看懂,意思是说如果重复创建bean的话,则会执行这段逻辑。
4.如果构造函数是无参的,则执行instantiateBean,否则执行autowireConstructor,因为大多数单例bean,我们都是无参的,这里重点看下instantiateBean这个方法逻辑。
5.instantiateBean内部的逻辑,会通过策略模式选择,使用何种方式生成,beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); 一种是通过反射机制,一种是通过cglib机制。当bean方法都没有被重写,即bd.getMethodOverrides().isEmpty()为空,则执行反射,否则使用org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy#instantiateWithMethodInjection进行生成。
6.使用反射机制实例化bean的最核心的两行代码:ReflectionUtils.makeAccessible(ctor);return ctor.newInstance(args);
7.使用cglib代理实例化bean的核心代码:
2.对bean填充属性的流程:
1.核心会调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyPropertyValues方法,此方法内,会调用org.springframework.beans.factory.support.BeanDefinitionValueResolver对BeanDefinition进行解析。
2.继续会调用org.springframework.beans.factory.support.BeanDefinitionValueResolver#resolveValueIfNecessary对bean的属性的value进行解析,这里会对value的类型进行多次判断,例如,RuntimeBeanReference,ManagerList,ManagerSet等。如果value类型是RuntimeBeanReference,根据debug实践发现,如果对象是引用类型的话,即会进入RuntimeBeanReference的逻辑内,首先会判断引用是否为父引用,如果是父引用,就进入了递归逻辑beanFactory.getParentBeanFactory().getBean(refName);如果不是父引用,也会进入递归逻辑beanFactory.getBean(refName)。这样会递归去寻找bean依赖的属性的bean。
3.初始化过程
在完成对bean的属性填充后,AbstractAutowireCapableBeanFactory#initializeBean方法会被调用。此方法内部,会先执行aware的逻辑,即调用AbstractAutowireCapableBeanFactory#invokeAwareMethods,如果一个bean实现了aware接口,那么实现该接口的方法就会被回调。例如:一个bean实现,org.springframework.beans.factory.BeanFactoryAware这个接口,那么org.springframework.beans.factory.BeanFactoryAware#setBeanFactory这个方法就会被回调。其次会执行,实现org.springframework.beans.factory.config.BeanPostProcessor这个接口的类,postProcessBeforeInitialization这个方法会被回调。再次,实现org.springframework.beans.factory.InitializingBean这个接口的类,afterPropertiesSet这个方法会被回调。再次自定义的回调方法会被执行,例如在xml文件上指定的init-method,最后实现BeanPostProcessor这个接口的类,postProcessAfterInitialization方法会被回调。
整体流程init顺序:
- 实现各种aware接口的类的方法会被回调。
- 实现BeanPostProcessor接口类的postProcessBeforeInitialization方法会被回调。
- 实现InitializingBean接口类的afterPropertiesSet方法会被回调。
- 在bean上指定的自定义init方法会被回调。
- 实现BeanPostProcessor接口类的postProcessAfterInitialization方法会被回调。
总结
整体Spring bean的加载过程,分为实例化阶段、填充属性阶段、初始化阶段。这三个阶段都完成后,就会把bean放入map缓存内,其实上一个文章,Spring是如何解决循环依赖的,也提到了bean加载的这三个流程。两篇文章结合起来分析会更全面些。在日常开发,我们关心最多的还是bean的初始化阶段,初始化阶段见上文是分成了五个步骤。对于这个顺序了解后,我们可以在不同的阶段,去拓展做不同的事情。