一篇文章让你彻底搞懂Bean后置处理器及执行时机

Bean生命周期涉及到的所有后置处理器及其执行时机

看了本篇文章,你会有如下收获

  1. 了解Bean生命周期流程
  2. 清楚有哪些后置处理器,及其在bean生命周期他们的执行时机
  3. "实诚"动态debug gif
香蕉君图片.jpg
  1. 看到满满的干货,然后才能和面试官对线
image

要想看懂这篇文章,你应该大致了解Spring的大致执行流程,不过不了解的小伙伴别担心,看看下面这段话

对下面流程不太熟悉的小伙伴也不需要担心,大概了解就行

[图片上传失败...(image-485ddf-1598633659159)]](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f3f13ff5e57945059002d0762cab067b~tplv-k3u1fbpfcp-zoom-1.image)

执行流程里面的 postProcessor 主要是用来在某个 生命周期 执行的时机点 调用而已

我都说到这个份儿上了,童鞋们最好都跟着Debug一下噢

言归正传 有个大前提:这里讨论的是,在容器refresh末尾的时候,需要完成Bean工厂初始化回调(finishBeanFactoryInitialization, 在回调的最后会预先加载Bean(preInstantiateSingletons),从而调用 getBean的逻辑来完成初始化

重要的话说n次 最好跟着Debug噢,就拿你自己的web项目 debug也行

想下载源码写 test 的童靴,如果不会请在下面评论区告诉我,我会补上Spring源码搭建的教材噢!

如果还嫌麻烦,我可以把我搭建好的项目传到gitee或者github,大家拉下来就能用了。

好,铺垫到这儿,我们开始吧

一、接管bean创建逻辑,返回自定义bean

从getBean流程开始,当bean创建的时候需要提前解析这个beanclass

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    // 如果这个bean没有被解析过,这里第一次进来肯定没解析过
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        // 重要!!!合成类知识,不想看这一大段文字,可以直接跳过,到下面if语句中
        // 这里的Synthetic指的是这个类是不是合成类,比如当这个类有个内部类的时候,这个类不能访问到内部类的私有变量
        // 但是这里jvm想要支持,怎么办呢?
        // 所以它采取了一种策略,创建一个新的类出来,合成这个类和内部类,使程序员在使用的时候看起来,可以直接访问内部类,这里不展开了
        // 感兴趣的兄dei可以自己写个类,看看class文件,会多出来一个 xxx1.class
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            // 看到这儿,从方法名就可以初步猜测这里是推断出class对象的
            // 但是他是怎么推断出来的呢,emmmmm,嘿嘿,这里挖个坑,后面讲
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 这里开始正式调用后置处理器,系统内置的后置处理器啥都没干
                // 除非你自己写了个后置处理器,看下个代码框
                // 而且你这个后置处理器提前给别人返回了一个bean,那么就会直接进入下面的判断完成初始化,直接结束
                // 如果你的公司想要自己去实现bean的初始化流程,那么就应该在这里实现
                // 之后Spring就会直接返回你给的这个对象,如下所示
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    // 执行后置处理,不同时机
                    // 下面有自定义的例子,gif演示
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}
自定义解析bean

[图片上传失败...(image-382692-1598633659159)]](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/443aec3ebb5c476382e55f3af28e46c4~tplv-k3u1fbpfcp-zoom-1.image)

  • 值得一提的是,除了我们自己可以在这里添加自定义bean返回,如果我们开启了自动代理,Spring也会把我们自定义的bean进行代理,感兴趣的童鞋可以 在配置类上加个 @EnableAspectJAutoProxy,写个Aspect切面指定到我们的A类试试

二、自行推断构造方法

我们继续去看第二个bean生命周期的执行时机,接下来,Spring就会去创建bean,那么问题来了,要创建一个bean,首先创建它的对象,如何创建对象?通过构造方法 反射创建?没错,但如果你提供了多个构造方法,我怎么知道要用哪个构造方法创建呢(下节详解,这里大概知道就行)Spring自己对构造方法做了推断,而推断逻辑则是放在了 AutowiredAnnotationBeanPostProcessor 中去推断

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
        throws BeansException {

    if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            // 可以自己去实现SmartInstantiationAwareBeanPostProcessor 的 determineCandidateConstructors
            // 从而实现覆盖 AutowiredAnnotationBeanPostProcessor 完成自定义
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
                if (ctors != null) {
                    return ctors;
                }
            }
        }
    }
    return null;
}

Spring 通过 AutowiredAnnotationBeanPostProcessor 实现的 推断构造方法,我们挖个坑,放到下篇专门讲解推断构造方法讲。

来来来,干了这一杯,还有··

对不起串台了

来来来,我们自己写个超简单的自定义后置处理器实现推断构造方法,去覆盖Spring自己的推断方法

image
@Component
public class CustomSmartInstantiationawareBPP implements SmartInstantiationAwareBeanPostProcessor {
    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("自己来推断构造方法");
        return beanClass.getDeclaredConstructors();
    }
}

结果:


getBean在解析bean之前返回bean自定义

可以看到创建所有bean的时候都被我们自定义的替换了

三、合并bean

首先我们来搞清楚一件事,什么是合并bean,在Spring中存在 三个BeanDefinition

  1. RootBeanDefinition 父BD
  2. ChildBeanDefinition 子BD
  3. GenericBeanDefinition 既可作用于父BD,又可是于子BD

现在有这么个情况,和java继承思想类似,当某个子BD继承了父BD,在使用时可以通过子BD操作父类属性(子类继承父类)。
所以必须要合并一下BD,让子类也有父类的属性

父子BD解释通了。那为什么不直接用GenericBD,或许是历史遗留原因,现在的版本必须向前兼容,故而必须保留。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // Allow post-processors to modify the merged bean definition.
    // 这里已经写得很清楚了,允许后置处理器去修改合并bean,我们来看看到底是哪个beanPostProcessor完成合并bean的呢?
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }

    ·······
}

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof MergedBeanDefinitionPostProcessor) {
            MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
            bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
        }
    }
}

CommonAnnotationBeanPostProcessor中,主要找 生命周期PostConstruct和PreDestroy切入点和资源切入@Resource xml的WebServiceRef 和 EJB

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    // 遍历所有方法,找到所有 @PostConstruct 和 @PreDestroy 注解的方法 并把他们放到 bd 中 把他们放入 bd 的 checkedInitMethods 和 checkedDestroyMethods属性中
    // 这里是调用了父类 “InitDestroyAnnotationBeanPostProcessor” 的方法
    super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
    // 遍历所有字段和方法,找到所有 @Resource 和 javax.xml.ws.WebServiceRef 和 javax.ejb.EJB 把他们放入 bd 的 checkedElements属性中
    InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}

AutowiredAnnotationBeanPostProcessor中,主要找 所有带了 @Autowired的属性和方法 (static无论方法属性都不行)

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    // 找到所有有 @Autowired 的字段和注解放入 bd 的 checkedElements中
    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}

接下来,我们自己实现一个后置处理器,来找一个我们自己定义的注解,并把它也存到bd中

@Component
public class CustomMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
    // 模拟autowired注解解析流程
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        // 第一步先找到注解,封装信息
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        // 第二步将注解信息注入 bd中
        metadata.checkConfigMembers(beanDefinition);
    }

    private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);

    // 搞个和autowired类似的
    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
        InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized (this.injectionMetadataCache) {
                metadata = this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }
                    metadata = buildAutowiringMetadata(clazz);
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
        return metadata;
    }

    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
            // 查找所有带了字段
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                if (field.isAnnotationPresent(ZWL.class)) {
                    if (Modifier.isStatic(field.getModifiers())) {
                        return;
                    }
                    boolean required = field.getAnnotation(ZWL.class).required();
                    String requiredStr = required? "必输":"非必输";
                    // 用来保存 注解信息,这样下次需要去注入时,再通过该element注入就好
                    System.out.println("找到一个ZWL注解,在" + clazz.getSimpleName() + "类中,是" + requiredStr + "的");
                    currElements.add(new ZWLFieldElement(field, required));
                }
            });

            elements.addAll(0, currElements);
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);

        // 返回封装后解析到的信息,用InjectionMetadata统一处理
        return new InjectionMetadata(clazz, elements);
    }

    private class ZWLFieldElement extends InjectionMetadata.InjectedElement {

        private final boolean required;

        private volatile boolean cached = false;

        @Nullable
        private volatile Object cachedFieldValue;

        public ZWLFieldElement(Field field, boolean required) {
            super(field, null);
            this.required = required;
        }

        @Override
        protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
            // 注入bean
        }
    }
}

下面是良心的debug gif

image

四、提前使用工厂暴露代理对象

就如我们在上一篇文章,循环依赖提到的,传送门 ,在过程 A->B->A 给B注入A对象时,如果A已经被代理,那么必须给他注入一个代理对象才行,所以这个地方就是要通过工厂来生产了,而这个工厂的运作方式,就是通过后置处理器返回的代理对象

上代码,一清二楚

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 调用工厂方法生产
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

// 工厂方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                // 这么多后置处理器中有AnnotationAwareAspectJAutoProxyCreator 的 getEarlyBeanReference方法 创建了一个代理对象
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    return exposedObject;
}


正经的分割线,预警!接下来的两个后置处理器执行时机,是在注入属性时执行的


五、在bean注入属性前,可以对bean做一些判断修改,也可以直接中断bean属性注入(判断是否需要继续注入属性)

// 在这里 Spring内置的beanPostProcessor 什么事也没干
// 所以只能我们自定义一个
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                continueWithPropertyPopulation = false;
                break;
            }
        }
    }
}

// 来看看我们的自定义的例子,这里复用了之前的 CustomInstantiationAwareBPP
@Component
public class CustomInstantiationAwareBPP implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    Object result = null;
    if (beanName.equals("A")) {
        System.out.println("在初始化之前来整一个A");
        result = new ObjectA();
    }
    // 避免返回自定义对象,结束创建bean
    // return result;
    return null;
}

// 新的在这里!!!
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    System.out.println("在属性真正注入之前对" + beanName + "bean做些小动作");
    // 是否继续注入属性,true则继续
    return true;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (beanName.equals("A")) {
        System.out.println("A已经整完了,好了,拿走吧");
    }
    return bean;
}
}

执行的结果当然就是打印出来了这句话

image

六、属性注入

后置处理器的执行点

PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
    if (pvs == null) {
        pvs = mbd.getPropertyValues();
    }
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 修改bean的propertyValues
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                if (filteredPds == null) {
                    filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                }
                // 改方法已经遗弃不建议使用
                pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    return;
                }
            }
            pvs = pvsToUse;
        }
    }
}

这里 CommonAnnotationBeanPostProcessor 会去注入之前提到过的 @ResourceWebServiceRefEJB的属性或者调用方法 设置值

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    // 还是和前面合并bean的功能一样,查找@Resource等信息,如果之前有解析过,那么这里就不会解析了,直接拿出缓存中的值
    InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
    try {
        // 上次是放到了将这些属性注入到了BD中,这次是注入到Bean中
        metadata.inject(bean, beanName, pvs);
    } catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
    }
    return pvs;
}

同样的AutowiredAnnotationBeanPostProcessor 也是在这里完成属性注入的,这里的 代码逻辑就是找到 @Autowired 的属性或方法 然后查找它合适的值然后注入,至于如何查找值,这个知识点下篇文章详解

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
        metadata.inject(bean, beanName, pvs);
    }
    catch (BeanCreationException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
    return pvs;
}

最后照例,我们自己的 后置处理器,还是沿用之前的 CustomInstantiationAwareBPP

@Component
public class CustomInstantiationAwareBPP implements InstantiationAwareBeanPostProcessor {

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    Object result = null;
    if (beanName.equals("A")) {
        System.out.println("在初始化之前来整一个A");
        result = new ObjectA();
    }
    // 避免返回自定义对象,结束创建bean
    // return result;
    return null;
}

@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    System.out.println("在属性真正注入之前对" + beanName + "bean做些小动作");
    // 是否继续注入属性,true则继续
    return true;
}

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    System.out.println("对bean的PropertyValues 做修改,然后注入对应属性");
    return pvs;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (beanName.equals("A")) {
        System.out.println("A已经整完了,好了,拿走吧");
    }
    return bean;
}
}

又到了画分割线的季节,下面才是猛男该看的东西

多图预警!!!


image
image
image
image

也就一般这么猛,言归正传,我们继续

接下来就是在bean完成属性注入后,对bean进行初始化的执行时机

七、在初始化前,调用各种aware

首先来看下初始化整体的调用逻辑

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

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

    try {
        // 调用实现的初始化的方法
        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()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

初始化之前的切入点

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

首先看 ApplicationContextAwareProcessor 主要是去触发一些实现了环境事件监听资源load``信息发布等等事件接口

@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    AccessControlContext acc = null;

    if (System.getSecurityManager() != null &&
            (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                    bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                    bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
        acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    }
    // 这个acc就是和资源、环境有关的aware,执行需要doPrivileged
    if (acc != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareInterfaces(bean);
            return null;
        }, acc);
    }
    else {
        invokeAwareInterfaces(bean);
    }

    return bean;
}

private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
        }
        if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        }
        if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
        }
        if (bean instanceof ApplicationEventPublisherAware) {
            ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
        }
        if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
        }
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
        }
    }
}

环境相关的接口都invoke后,自定义的后置处理器开始执行

@Component
public class CustomInstantiationAwareBPP implements InstantiationAwareBeanPostProcessor {
// 还是这个类,熟悉的味道,伴随着bean的整个实例化生命周期
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (beanName.equals("A")) {
        System.out.println("在真正初始化之前,对bean A 修改一下");
    }
    return bean;
}

// 其他生命周期的调用方法
}

还记得我们前面说的CommonAnnotationBeanPostProcessor合并bean的时候,同样是这个后置处理器,调用它的父类InitDestroyAnnotationBeanPostProcessor@PostConstruct@PreDestroy注解的方法存到当前这个后置处理器了么,下面就是要invoke他们的时候了

image
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // 找到之前 找出的 `@PostConstruct` 和 `@PreDestroy`
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    try {
        // 执行他们
        metadata.invokeInitMethods(bean, beanName);
    }
    catch (InvocationTargetException ex) {
        throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
    }
    return bean;
}

第八次、在完成bean的初始化后 - 完成代理

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

这里就不贴自定义的后置处理器了,和前面before大同小异

第一个后置处理器是PostProcessorRegistrationDelegate

他首先会check一下,在当前正在创建的bean时,不是BeanPostProcessor,不是spring的基础类型bean,并且!!! 重点来了:如果当前工厂的所有bean 后置处理器的数量小于实际执行后置处理器数量,就会打个info,这里有很多人踩坑。先看下代码:

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    if (!(bean instanceof BeanPostProcessor) && !isInfrastructureBean(beanName) &&
            this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
        if (logger.isInfoEnabled()) {
            logger.info("Bean '" + beanName + "' of type [" + bean.getClass().getName() +
                    "] is not eligible for getting processed by all BeanPostProcessors " +
                    "(for example: not eligible for auto-proxying)");
        }
    }
    return bean;
}

踩什么坑?比如,看下面打的日志,Spring说 你当前这个bean,还没有准备好被所有后置处理器调用,比如自动代理(造成代理失败)。

这就是很多人突然发现自己项目,事务、AOP或者异步失效了,就很懵逼。

要怎么解决呢?

比如你为了省麻烦,不想自己单独开个配置类,在以前项目代码的一个使用比较低优先级的BeanPostProcessor(比如order很低的)来完成这个业务bean的注入。当注入这个bean的时候,因为处理事务、AOP的后置处理器还没加载,自然也没发代理这个bean,从而显得他们都失效

说人话就是,自己把业务bean放到,Spring的后置处理器前面实例化了

解决方法就是,不偷懒,自己搞个配置类放进去,保证在后面执行就ok

第二个是AbstractAutoProxyCreator

就是看你需不需要代理,需要就给你整个代理
这个地方要结合着,前面,循环依赖来看,当 A->B->A 时,A如果需要被代理,那么earlyProxyReferences就会有A的cache,从而在这里完成代理

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

最后一个起作用的是 ApplicationListenerDetector

这儿其实就看一行代码 this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);

将监听器当道环境中

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    if (bean instanceof ApplicationListener) {
        // potentially not detected as a listener by getBeanNamesForType retrieval
        Boolean flag = this.singletonNames.get(beanName);
        if (Boolean.TRUE.equals(flag)) {
            // singleton bean (top-level or inner): register on the fly
            this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
        }
        else if (Boolean.FALSE.equals(flag)) {
            if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
                // inner bean with other scope - can't reliably process events
                logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
                        "but is not reachable for event multicasting by its containing ApplicationContext " +
                        "because it does not have singleton scope. Only top-level listener beans are allowed " +
                        "to be of non-singleton scope.");
            }
            this.singletonNames.remove(beanName);
        }
    }
    return bean;
}

啪啪啪 终于tm的写完了

之后就是一些getBean的收尾工作,清除缓存、添加bean到单例池等等

image

下一篇文章我们来填上面的坑 - 创建bean时如何推断一个bean的构造方法

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,273评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,349评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,709评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,520评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,515评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,158评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,755评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,660评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,203评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,287评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,427评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,122评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,801评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,272评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,393评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,808评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,440评论 2 359