Bean加载时机

Spring 容器内的Bean是在什么时候加载的呢?在Spring内有一个配置可以管控Bean加载的时机,即Lazy-Init,在绝大多数情况下,通常这个配置是false。把懒加载置为false的原因,是希望在Spring Ioc容器初始化的时候,就把所有的Bean都给初始化好。这样可以缩短系统接口的RT。对lazy-init属性的处理,实际的处理是在DefaultListableBeanFactory这个基本容器preInstantiateSingletons方法中完成的

DefaultListableBeanFactory类内preInstantiateSingletons方法:

spring 项目启动就加载的注解 spring加载过程_实例化

调用时机: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的核心代码:

spring 项目启动就加载的注解 spring加载过程_java_02

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顺序:

  1. 实现各种aware接口的类的方法会被回调。
  2. 实现BeanPostProcessor接口类的postProcessBeforeInitialization方法会被回调。
  3. 实现InitializingBean接口类的afterPropertiesSet方法会被回调。
  4. 在bean上指定的自定义init方法会被回调。
  5. 实现BeanPostProcessor接口类的postProcessAfterInitialization方法会被回调。

总结

整体Spring bean的加载过程,分为实例化阶段、填充属性阶段、初始化阶段。这三个阶段都完成后,就会把bean放入map缓存内,其实上一个文章,Spring是如何解决循环依赖的,也提到了bean加载的这三个流程。两篇文章结合起来分析会更全面些。在日常开发,我们关心最多的还是bean的初始化阶段,初始化阶段见上文是分成了五个步骤。对于这个顺序了解后,我们可以在不同的阶段,去拓展做不同的事情。