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源码的解读也可以帮助自己学习设计模式、代码思想。