本系列所有基于 Spring 5.2.2.BUILD-SNAPSHOT
版本。由于 Spring 整个体系太过于庞大,因此只会进行关键部分的源码解析。html
本篇文章主要介绍 Spring IoC 容器中 bean
的初始化阶段。java
咱们在Spring IoC bean 的建立一文中分析建立 bean
实例的主要流程,此时建立出来的 bean
仍是个属性未赋值的实例,在建立完以后会进入 populateBean()
方法,即进入属性赋值阶段。咱们简单回顾一下,上次分析过的 doCreateBean()
方法:git
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // 实例化 bean BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { // 若是bean的做用域是singleton,则须要移除未完成的FactoryBean实例的缓存 instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // 经过构造函数反射建立bean的实例,可是属性并未赋值,见下文详解 instanceWrapper = createBeanInstance(beanName, mbd, args); } // 获取bean的实例 final Object bean = instanceWrapper.getWrappedInstance(); // 获取bean的类型 Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { // BeanDefinition 合并后的回调,见下文详解 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } // 省略异常处理... mbd.postProcessed = true; } } // bean的做用域是单例 && 容许循环引用 && 当前bean正在建立中 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); // 若是容许bean提早曝光 if (earlySingletonExposure) { // 将beanName和ObjectFactory造成的key-value对放入singletonFactories缓存中 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } Object exposedObject = bean; try { // 给 bean 的属性赋值 populateBean(beanName, mbd, instanceWrapper); // 初始化 bean exposedObject = initializeBean(beanName, exposedObject, mbd); } // 省略部分代码 }
上篇文章分析了 populateBean()
方法,此次咱们总店分析 initializeBean()
方法。github
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { // BeanAware的接口回调,见下文详解 invokeAwareMethods(beanName, bean); Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // BeanPostProcessor的postProcessBeforeInitialization()回调,也就是bean初始化前的回调 // 在 ApplicationContextAwareProcessor实现的postProcessBeforeInitialization方法中会执行 // ApplicationContext Aware的接口回调。 // InitDestoryAnnotationBeanPostProcessor的postProcessBeforeInitialization()中会执行 // 标注了@PostConstruct注解的方法。 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // 调用bean的自定义初始化方法,如afterPropertiesSet,XML中的init属性指定的方法等 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()) { // BeanPostProcessor的postProcessAfterInitialization()回调,也就是bean初始化后的回调 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { // BeanNameAware接口方法回调 if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } // BeanClassLoaderAware接口方法回调 if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } // BeanFactoryAware接口方法回调 if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware)bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
经过实现这些 Aware
接口的 bean
的被初始化以前,能够取得一些相对应的资源,好比 beanName
、beanFactory
等。spring
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // 遍历全部注册的BeanPostProcessor实现类,调用postProcessBeforeInitialization方法 for (BeanPostProcessor processor : getBeanPostProcessors()) { // 在bean初始化方法执行前,调用postProcessBeforeInitialization方法 Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
上面方法主要是调用了 BeanPostProcessor
的 postProcessBeforeInitialization()
方法,下面咱们看一下 BeanPostProcessor
接口的定义:缓存
public interface BeanPostProcessor { /** * bean初始化前调用,此时bean已经实例化而且属性已经赋值,Aware接口已经回调;返回非 {@code null} 会使用返回的bean */ @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } /** * bean初始化后调用,返回非 {@code null} 会使用返回的bean */ @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { // bean是否实现InitializingBean接口 boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { // 调用afterPropertiesSet方法 ((InitializingBean) bean).afterPropertiesSet(); } // 调用自定义的init方法,例如XML中init-method属性设置的方法 if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } }
咱们知道设置 bean
的初始化方法其实有三种方式 @PostConstruct
、InitializingBean
、自定义初始化方法,一个 bean
同时实现这三种方式时,调用顺序以下:app
@PostConstruct
InitializingBean#afterPropertiesSet()
从上面方法能够很容易的看出 InitializingBean
接口的 afterPropertiesSet()
方法先于自定义初始化方法调用,那么 @PostConstruct
注解标注的方法在什么时候调用的呢?玄机就在上面介绍的 BeanPostProcessor
接口,InitDestroyAnnotationBeanPostProcessor
实现了该接口并重写了 postProcessBeforeInitialization()
方法调用了标注 @PostConstruct
注解的方法。我会在后续文章分析其实现。函数
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // 遍历全部注册的BeanPostProcessor实现类,调用postProcessAfterInitialization方法 for (BeanPostProcessor processor : getBeanPostProcessors()) { // 在bean初始化方法执行后,调用postProcessBeforeInitialization方法 Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
本篇文章主要分析了 Spring IoC bean
的初始化阶段流程,Spring 在此阶段也提供了2个扩展点;分别是 bean
的初始化前和初始化后,也就是 BeanPostProcessor
接口,该接口十分重要其它 processor
接口都是直接或间接在此接口上扩展出来的。post
最后,我模仿 Spring 写了一个精简版,代码会持续更新。地址:https://github.com/leisurexi/tiny-spring。this