Spring Bean的一生

229 阅读11分钟

Spring Bean的创建是在Spring在启动时就会执行的任务,在bean创建的过程中也非常经典地体现了SpringIOC的特性。大致来说,bean的一生最重要的就是实例化与初始化这两个阶段,在这两个大阶段中还有很多值得剖析的功能实现,例如推断构造方法、循环依赖、beanPostProcessor的应用等。我将用一个简单的spring项目来展示一个bean在spring启动时都将经历什么。

启动方式如下。

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();

appConfig中定义了这两个简单类,基础类中没有任务属性,只是创建一个对象,后续会对其稍作修改,来看下不同情况下的bean变化。

public class AppConfig {

    @Bean
    public UserService userService(){
        return new UserService();
    }

    @Bean
    public OrderService orderService(){
        return new OrderService();
    }
}

public class OrderService {
}

public class UserService {
    @Autowired
    private OrderService orderService;

    public void test(){
        System.out.println("test");
    }
}

实例化

实例化是一个大过程,还需要分为几个小步骤。个人理解实现化就像是 A a = new A();的过程,但是这个过程是由spring来完成的,所以这也是spring IOC 特性。

创建beanFactory

在refresh()前,一个基础的beanFactory就已经创建完成。

// Tell the subclass to refresh the internal bean factory.
//告诉子类刷新内部bean工厂。
// AbstractApplicationContext#refresh
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

返回的beanFactory是DefaultListableBeanFactory

类的,spring对这个类的解释是:“一个基于bean定义元数据的成熟bean工厂,可通过后处理器扩展。在使用bean之前需要先注册beanDefinition”。所在在这里也可以看到,一些系统的基础bean以及appconfig的beanDefinition已经创建好了。beanDefinitionMap中key=className,value是一个BeanDefinition对象,包含了beanClass、scope、等属性。

最原始的类是BeanFactory,是一个生成bean的工厂,它是一个interface,定义了一些bean的基本行为与属性。

完善beanFactory

在这个方法中都是对beanFactory的属性的一些填充。比如classLoader,postProcessor等。classLoader是内部由ClassUtils.getDefaultClassLoader()方法获取,debug能看到结果是AppClassLoader。

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

在这个方法中完成了对BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor这两个接口的调用。

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

这个方法是对所有实现了BeanPostProcessor的类,注册入BeanPostProcessor,依次对实现了PriorityOrdered、Ordered、其它自定义的类进行注册并实例化。

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

实例化

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

beanFactory都准备好后,就可以进行真正的实例化了。

在DefaultListableBeanFactory#preInstantiateSingletons方法中开始执行真正的实例化接口。

使用这个判断过滤,抽象的、非单例的、lazy注解的都不会在启动时生成bean。

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit())

判断通过后,会在AbstractBeanFactory#doGetBean创建bean。普通的单例bean都会在这段代码中生成。getSingleton方法会先去从单例池singletonObjects中去获取,如****果没有就会执行createBean(beanName, mbd, args);内部会再调用AbstractAutowireCapableBeanFactory#doCreateBean

// Create bean instance.
if (mbd.isSingleton()) {
	sharedInstance = getSingleton(beanName, () -> {
		try {
			return createBean(beanName, mbd, args);
		}
		catch (BeansException ex) {
			// Explicitly remove instance from singleton cache: It might have been put there
			// eagerly by the creation process, to allow for circular reference resolution.
			// Also remove any beans that received a temporary reference to the bean.
			destroySingleton(beanName);
			throw ex;
		}
	});
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

在AbstractAutowireCapableBeanFactory#createBean方法中有这样一段代码,在resolveBeforeInstantiation中实现了对BeanPostProcessors的实现,如果在自定义的实例化前方法中已经完成了实例化,那就会继续执行AfterInitialization的初始化后方法,并返回bean,不再进行接下来的实例化方法。

// AbstractAutowireCapableBeanFactory#createBean部分代码:
try {
	// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	if (bean != null) {
		return bean;
	}
}
catch (Throwable ex) {
	throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
			"BeanPostProcessor before instantiation of bean failed", ex);
}

// resolveBeforeInstantiation 部分内部代码:
if (targetType != null) {
	bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
	if (bean != null) {
		bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
	}
}

创建实例

由AbstractAutowireCapableBeanFactory#createBeanInstance方法返回bean实例。

由于我的例子是由Appconfig启动,并用@Bean注解,所以在一开始spring会扫描所有带有@Bean的方法,将方法名称设置到BeanDefinition的FactoryMethodName属性中,所以会使用这个代码返回实例。

if (mbd.getFactoryMethodName() != null) {
	return instantiateUsingFactoryMethod(beanName, mbd, args);
}

推断构造方法

其它的bean都将通过推断构造方法的方式来进行实例化。

方法内部逻辑可以总结为:

首先从candidateConstructorsCache中获取是否存在构造函数的缓存,如果有直接返回;

如果没有从beanClass获取所有的构造方法,再遍历:在findAutowiredAnnotation方法中找到是否包含Autowired、Value注解。

1.一个注解都没有

1.1 有多个构造方法,返回null

1.2 只有一个有参构造,返回当前方法

1.3 只有一个无参构造,返回null

2.至少有一个注解

2.1只有一个require为true,返回当前方法

2.2有多个require为true,抛异常

2.3 有一个require为true,其他为false,抛异常

2.4没有requeir为true,返回所有require为false的构造方法与无参构造函数

Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

如果返回有值,会使用autowireConstructor返回实例,内部实现会去获取参数,参数也会通过getBean拿到,如果是返回null的情况,会使用instantiateBean方法,会使用默认的无参构造方法,使用反射实例化。

在bean实例化完成后会在addSingletonFactory方法中,将原始对象factory存入三级缓存singletonFactories,在二级缓存earlySingletonObjects中删除,在一级缓存singletonObjects中加入,这个缓存会在之后解决循环依赖的问题。

BeanDefinition后置处理

在AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors方法中可以实现对beanDefinition的后置处理。

对userService稍作修改,增加number字段。

@Data
public class UserService {
    @Autowired
    private OrderService orderService;

    private int number;

    public void test(){
        System.out.println("test");
    }
}

新增一个我们自定义的postProcess,可以让它对beanDefiniton进行修改。

@Component
public class MyMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        if (beanName.equals("userService")){
            beanDefinition.getPropertyValues().add("number",33);
        }
    }
}

在spring内部,也有一些类实现了MergedBeanDefinitionPostProcessor ,扫描注入点,并存在各自的injectionMetadataCache对象中,为后续的自动注入埋点。

AutowiredAnnotationBeanPostProcessor中扫描了Autowired、Value

CommonAnnotationBeanPostProcessor中扫描了Resource,PostConstruct、PreDestroy方法存入了lifecycleMetadataCache

自动注入

实例化完成后,就可以对其中的属性进行修改了,在这个方法中会完成属性定义:AbstractAutowireCapableBeanFactory#populateBean

在getBeanPostProcessors方法获取到所有beanPostProcessor的类后,循环依次对实现了InstantiationAwareBeanPostProcessor的类执行ibp.postProcessProperties,在对这个方法debug时可以看到orderService作为userService的成员对象。

自动注入是由AutowiredAnnotationBeanPostProcessor实现,先从injectionMetadataCache中获取被注释的方法与字段,执行inject,最终在AutowiredFieldElement类(AutowiredAnnotationBeanPostProcessor的内部类)中的inject方法中通过field.set(bean, value);实现了注入。这里的value就是生成的OrderService的bean。调用链:

InjectionMetadata#inject ->

AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject(还有另一个子类AutowiredMethodElement用来处理用@Autowired修改的方法) ->

beanFactory.resolveDependency ->

DefaultListableBeanFactory#resolveDependency ->

doResolveDependency ->

descriptor.resolveCandidate ->

beanFactory.getBean(beanName)

到了getBean这一步,就是去创建orderService的bean了。

循环依赖

如果到getBean(orderService)的时候,还需要注入userService,就是当orderService与userService互相依赖的时候,就需要用到三级缓存了,先简单介绍一下三级缓存:

singletonObjects:一级缓存,也叫单例池,存放创建完的bean

earlySingletonObjects:二级缓存,存放还未创建完的bean

singletonFactories:三级缓存,存放创建早期bean的工厂

1.首先在创建实例时,会在addSingletonFactory方法中,已经将userService刚执行完构造方法后的对象存入三级缓存中了,这时候的orderService还是null。

2.在populateBean方法自动注入orderService的时候,由于orderService还未创建,所以会执行getBean创建

3.进入到orderService的创建,执行完构造方法后,也将对象放入三级缓存中,这时候的userService也是null。

4.orderService构造完后,要进行对userService的注入,根据ibp.postProcessProperties调用链,最终会执行beanFactory.getBean(userService)。如下图,将会在getSingleton方法中从三级缓存singletonFactories中拿到刚才刚执行完构造的userService。这时被注入的userService还是刚执行完构造时的对象。

getSingleton的内部实现如下图。现在的情况是,一级缓存中没有这两个对象;二级缓存中已将userService放入,且它的成员orderService为null;三级缓存中只有orderService,它的value是刚构造完的orderService的beanFactory。

5.getBean拿到userService后,会在AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject(ibp.postProcessProperties的注入类的实现)方法中执行field.set()。完成真正的依赖注入。

6.这时orderService已创建完成,返回到DefaultSingletonBeanRegistry#getSingleton方法中,继续执行

此时各级缓存的情况如下图。一级缓存已有orderService,内部成员userService也已经有值了;二级缓存中是userService,可以看到和一级缓存中orderService的内部userService的hash值是一样的,所以是同一个对象;三级缓存中没有值,因为此时orderService和userService都已经有实例对象了,所以objectFactory已不再需要。

7.此时orderService的生命中的创建已全部走完,所以会回到userService的注入时,也说第5步中ibp.postProcessProperties的注入实现,这时候再执行field.set就能实现循环依赖了。之后也会像第6步中,将userService也放入一级缓存中。

执行Aware

执行完populateBean方法后,接下来就是执行initializeBean,在这个方法内部就是执行的初始化,但是会先在invokeAwareMethods中执行一些回调。

BeanNameAware:回传beanName

BeanClassLoaderAware: 回传bean的类加载器

BeanFactoryAware:回传beanFactory

初始化

initializeBean中实现了上面提到到的aware、初始化前、初始化、初始化后。

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	if (System.getSecurityManager() != null) {
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			invokeAwareMethods(beanName, bean);
			return null;
		}, getAccessControlContext());
	}
	else {
        // 1.aware调用
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
        // 2.初始化前
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	try {
        // 3.初始化
		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()) {
        // 4.初始化后
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}

	return wrappedBean;
}

初始化前

在applyBeanPostProcessorsBeforeInitialization方法中执行初始化前的方法,也是通过BeanPostProcessors接口的postProcessBeforeInitialization来实现,同样也可以通过自定义BeanPostProcessors来完成自定义的操作。在spring中也有一些应用:

ApplicationContextAwareProcessor中,执行了一些如环境变更、ApplicationContextAware等一系列的回调。

InitDestroyAnnotationBeanPostProcessor中,在findLifecycleMetadata方法中,从lifecycleMetadataCache对象中拿到在实例化后置处理时存入的PostConstruct、PreDestroy方法,再开始调用方法。

LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
	metadata.invokeInitMethods(bean, beanName);
}

在实例后置处理时,是将PostConstruct、PreDestroy都放入了,那为什么现在只执行了PostConstruct方法呢?这需要再看一下实例后置处理时是怎么执行的。CommonAnnotationBeanPostProcessor的后置处理器中先执行了父类的处理器。通过调用链:InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinition -> findLifecycleMetadata -> buildLifecycleMetadata。可以看到通过initAnnotationType与destroyAnnotationType区分了InitMethods与DestroyMethods。

ReflectionUtils.doWithLocalMethods(targetClass, method -> {
	if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
		LifecycleElement element = new LifecycleElement(method);
		currInitMethods.add(element);
		if (logger.isTraceEnabled()) {
			logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
		}
	}
	if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
		currDestroyMethods.add(new LifecycleElement(method));
		if (logger.isTraceEnabled()) {
			logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
		}
	}
});

又能在CommonAnnotationBeanPostProcessor的构造方法中已经将分别将PostConstruct -> InitAnnotationType,PreDestroy -> DestroyAnnotationType 建立了联系。

public CommonAnnotationBeanPostProcessor() {
	setOrder(Ordered.LOWEST_PRECEDENCE - 3);
	setInitAnnotationType(PostConstruct.class);
	setDestroyAnnotationType(PreDestroy.class);
	ignoreResourceType("javax.xml.ws.WebServiceContext");
}

接着在执行实例化前时,initDestroyAnnotationBeanPostProcessor.LifecycleMetadata#invokeInitMethods的实现中只获取了checkedInitMethods,就实现了只执行PostConstruct方法。

public void invokeInitMethods(Object target, String beanName) throws Throwable {
	Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
	Collection<LifecycleElement> initMethodsToIterate =
			(checkedInitMethods != null ? checkedInitMethods : this.initMethods);
	if (!initMethodsToIterate.isEmpty()) {
		for (LifecycleElement element : initMethodsToIterate) {
			if (logger.isTraceEnabled()) {
				logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
			}
			element.invoke(target);
		}
	}
}

初始化

invokeInitMethods方法中,首先会对实现了InitializingBean的类执行afterPropertiesSet方法。接着会使用反射执行init-method。

个人理解初始化就是对bean中的属性赋值的过程,用PostConstruct、afterPropertiesSet、init-method都可以实现相同的效果,区别只是执行的顺序不一样,以及使用的方式不一样。PostConstruct使用注解的方式,afterPropertiesSet使用接口实现的方式,init-method使用XML配置接口的方式。

初始化后

applyBeanPostProcessorsAfterInitialization又是一个beanPostProcessor的应用。同样也可以通过用自定义的方式来使用spring提供的这个扩展点。

到这里基本bean的创建就已经完成了。

销毁

bean的销毁是在容器关闭的时候,context.close()时触发的,并会执行PreDestroy方法。销毁一般用的比较少,所以只简单的了解一下。

流程图总结

bean的一生大部分都是在refresh()方法中调用AbstractApplicationContext#finishBeanFactoryInitialization完成的,最后来一张流程图来帮助理解。

通过上面对源码的剖析,可以看到在bean生命周期中,用到了很多beanPostProcessor,这也是spring提供的扩展点,能让程序员更灵活地控制bean的创建。

文中对于个人觉得比较重要的接口或对象都做了加粗处理,觉得可以仔细看看源码,常看常新。对于spring源码的解读也可以帮助自己学习设计模式、代码思想。