Spring后置处理器-postProcessBeanFactory

在refresh方法的invokeBeanFactoryPostProcessors方法中,后置处理器的执行流程

1、首先调用context传入的BeanDefinitionRegistryPostProcessor接口

2、调用Spring注入的BeanDefinitionRegistryPostProcessor接口(ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry => 包扫描,Import等)会添加到已执行的集合中

3、调用扫描出来的BeanDefinitionRegistryPostProcessor接口实现类(分三个级别调用)会添加到已执行的集合中

4、调用所有的BeanDefinitionRegistryPostProcessor接口的postProcessBeanFactory方法

5、调用context.add手动注入的BeanFactoryPostProcessor接口的postProcessBeanFactory方法(不会添加到已执行集合中)

6、最终获取容器中所有的BeanFactoryPostProcessor接口的实现类,逐一检查是否回调过,没有回调的根据优先级回调(context添加的BeanFactoryPostProcessor、spring扫描的BeanFactoryPostProcessor)

使用context.addBeanFactoryPostProcessor添加到的BeanFactoryPostProcessor接口的实现类会被执行两次

前面记录了ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry方法,接下来就会执行ConfigurationClassPostProcessor#postProcessBeanFactory方法

Spring注入的类中

ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor

EventListenerMethodProcessor 实现了 BeanFactoryPostProcessor

AutowiredAnnotationBeanPostProcessor 实现了BeanPostProcessor

CommonAnnotationBeanPostProcessor 实现了BeanPostProcessor

接下来主要分析ConfigurationClassPostProcessor#postProcessBeanFactory和EventListenerMethodProcessor#postProcessBeanFactory

后置处理器beanPostProcrssor的继承关系.png

InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor接口继承BeanPostProcessor接口,它内部提供了3个方法,再加上BeanPostProcessor接口内部的2个方法,所以实现这个接口需要实现5个方法。InstantiationAwareBeanPostProcessor接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置。AbstractAutowireCapableBeanFactory#createBean方法的Object bean = resolveBeforeInstantiation(beanName, mbdToUse);方法里面执行了这个后置处理器

/* 在目标对象实例化之前调用,方法的返回值类型是Object,我们可以返回任何类型的值。
* 由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(一般都是代理对象)。
* 如果该方法的返回值代替原本该生成的目标对象,
* 后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走
*/
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    return null;
}
/* 方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。
* 如果该方法返回false,会忽略属性值的设置;
* 如果返回true,会按照正常流程设置属性值。
* 方法不管postProcessBeforeInstantiation方法的返回值是什么都会执行
*/
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    return true;
}
// 在spring的工厂属性注入之前,自己指定属性的值
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    return null;
}
// 方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation方法返回false,该方法不会被调用。可以在该方法内对属性值进行修改
default PropertyValues postProcessPropertyValues(
    PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
    return pvs;
}

还有父接口BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法都是在目标对象被实例化之后,并且属性也被设置之后调用的

SmartInstantiationAwareBeanPostProcessor

智能实例化Bean后置处理器(继承InstantiationAwareBeanPostProcessor)

// 预测bean的类型
default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
    return null;
}
// 检测Bean的构造器,可以检测出多个候选构造器
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {

    return null;
}
// 循环引用的后置处理器,获得提前暴露的bean引用。主要用于解决循环引用的问题,只有单例对象才会调用此方法
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
    return bean;
}

MergedBeanDefinitionPostProcessor

// 在bean初始化之前合并一些东西到bd中 比如:bean的初始化回调和销毁回调方法
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
// 重置 BeanDefinition 缓存
default void resetBeanDefinition(String beanName) {}

ConfigurationClassPostProcessor

ConfigurationClassPostProcessor#postProcessBeanFactory这个方法的作用是通过用cglib增强配置类,准备在运行时为bean请求提供服务。也就是在Configuration注解类的 方法中调用 @Bean修饰的方法时,为了保证每一个bean都是单例,会首先去容器搜索@Bean修饰的这个对象是否在容器中存在,如果存在就直接返回容器中的对象,不存在就会调用@Bean对应的方法逻辑构建一个bean对象放入容器中并返回这个对象。以上这种机制是通过cglib代理中的拦截器实现的。

// ConfigurationClassPostProcessor
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // cglib 代理 ConfigurationClass
    enhanceConfigurationClasses(beanFactory);
    // 注册了 ImportAwareBeanPostProcessor bean的后置处理器(这个后置处理器非常重要)
    // postProcessProperties方法主要是为 EnhancedConfiguration 类注入一个beanFactory
    // postProcessBeforeInitialization 方法为 ImportAware 类型的bean注入一个 AnnotationMetadata
    beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
// ConfigurationClassPostProcessor
// 这个方法会找到bdMap中的所有配置类,任何一个配置类都会被 ConfigurationClassEnhancer 代替
// 区别的方式就是 full 和 lite
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    // 循环 bdMap
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        // full
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
            configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
        }
    }
    // 没有配置类去代理 直接返回
    if (configBeanDefs.isEmpty()) return;
    // 有配置类需要去一一代理,替换原bd中的class
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
        AbstractBeanDefinition beanDef = entry.getValue();
        // If a @Configuration class gets proxied, always proxy the target class 设置标识
        beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        // 为代理类配置他需要代理的类,使用同一个类加载器
        Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
        if (configClass != null) {
            // 生成代理对象
            Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
            if (configClass != enhancedClass) {
                // 把bd中的beanClass替换为代理对象
                beanDef.setBeanClass(enhancedClass);
            }
        }
    }
}

创建代理对象的逻辑

// ConfigurationClassEnhancer#enhance
// configClass 这个参数是需要代理的class
// classLoader 加载这个configClass的classLoader
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
    // 创建代理
    Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
    return enhancedClass;
}
// 创建一个新的cglib对象实例
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(configSuperClass);
    // 设置这个接口是为了注入一个属性 $$beanFactory 注入了beanFactory之后,就可以通过beanFactory去容器中获取对象
    // 这个接口继承了 BeanFactoryAware 接口,这个aware接口可以拿到beanFactory对象
    // 检查方法返回值的对象是否已经在容器中存在了
    enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
    enhancer.setUseFactory(false);
    // 生成名称策略
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
    // 注册一些方法拦截器  => 方法指的时每一个入栈的方法 => 在a方法中调用了b c方法,则这里需要拦截三次,每一个方法都会拦截
    enhancer.setCallbackFilter(CALLBACK_FILTER);
    enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
    return enhancer;
}
private Class<?> createClass(Enhancer enhancer) {
    Class<?> subclass = enhancer.createClass();
    // subclass 就是我们创建的代理对象
    // 这里就是为这个代理对象的静态方法注入这些方法拦截器(CALLBACKS)
    Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
    return subclass;
}
// 默认的前置处理
private static final Callback[] CALLBACKS = new Callback[] {
    new BeanMethodInterceptor(),
    new BeanFactoryAwareMethodInterceptor(),
    NoOp.INSTANCE
};

生成的代理对象如下所示:

public class AppConfig$$EnhancerBySpringCGLIB$$af448cfe extends AppConfig implements EnhancedConfiguration {
    public BeanFactory $$beanFactory;
    // 注入BeanFactory
    public final void setBeanFactory(BeanFactory var1) throws BeansException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_1;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$setBeanFactory$6$Method, new Object[]{var1}, CGLIB$setBeanFactory$6$Proxy);
        } else {
            super.setBeanFactory(var1);
        }
    }
    // 对@Bean方法的代理
    public final UserTest2 userTest2() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        // 如果存在方法拦截器,返回拦截器的intercept方法返回的值
        return var10000 != null ? (UserTest2)var10000.intercept(this, CGLIB$userTest2$1$Method, CGLIB$emptyArgs, CGLIB$userTest2$1$Proxy) : super.userTest2();
    }
}

拦截器

拦截器会拦截代理对象中的所有方法

1、BeanFactoryAwareMethodInterceptor

BeanFactoryAwareMethodInterceptor这个拦截器就是为代理对象中注入BeanFactory对象

// obj代理对象
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    // 获取 BEAN_FACTORY_FIELD = $$beanFactory 字段
    Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
    // 设置 $$beanFactory属性的值
    field.set(obj, args[0]);
    // Does the actual (non-CGLIB) superclass implement BeanFactoryAware?
    // If so, call its setBeanFactory() method. If not, just exit.
    if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
        return proxy.invokeSuper(obj, args);
    }
    return null;
}

可以看出设置的值是args[0],这里beanFactory的注入是ImportAwareBeanPostProcessor这个后置处理器在对象创建时将beanFactory对象传进来了。

// ImportAwareBeanPostProcessor#postProcessProperties
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    if (bean instanceof EnhancedConfiguration) {
        // 调用set方法的时候会被cglib代理中的拦截器拦截
        ((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
    }
    return pvs;
}

2、BeanMethodInterceptor @Bean方法的拦截器

核心方法intercept

// ConfigurationClassEnhancer.BeanMethodInterceptor
// 代理一个方法,在方法执行之前,检查容器是否存在方法返回的对象
// enhancedConfigInstance 代理对象
// beanMethod 配置类的方法
// beanMethodArgs 方法参数
// cglibMethodProxy 代理方法
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,MethodProxy cglibMethodProxy) throws Throwable {
    // 通过反射代理对象得到代理对象中的 beanFactory 对象
    ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
    String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
    /*
    首先,检查请求的bean是否是 FactoryBean。如果是这样,创建一个子类代理,拦截对getObject()的调用并返回任何缓存的bean实例。
    这确保了从 @Bean 方法中调用FactoryBean的语义与在XML中引用FactoryBean的语义相同
    检查 这个 &beanName 这个beanName在容器中是否存在对应的bd或者bean对象
    如果存在,则说明这个 beanName 是一个 factoryBean ,则不能返回它构造函数生成的对象
    那么我们需要返回这个类(beanName)的 getObject 方法返回的对象,所以需要对 beanName 这个类进行代理,返回 getObject 方法返回的对象
    同时在getObject方法调用的时候,spring 先去从容器获取 beanName 对应的bd或者bean 如果存在就不会执行getObject方法,直接返回从容器中获取的对象
    */
    if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
        factoryContainsBean(beanFactory, beanName)) {
        Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
        if (factoryBean instanceof ScopedProxyFactoryBean) {
            // 存在作用域的 FactoryBean 这里不需要处理这种
        }else {
            // 返回 factoryBean 的代理对象 => 对getObject方法进行拦截
            return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
        }
    }
    /**
     * isCurrentlyInvokedFactoryMethod 这个判断是决定是执行方法还是从荣容器中获取对象的关键判断
     * 前面说过,每调用一个方法都会被拦截,那么怎么判断调用的方法是不是以及被调用过了呢?
     * 也就是怎么确定这个方法是第一次调用,因为第一次调用需要执行方法中的方法体来创建对象
     * beanMethod 指的到当前调用的方法,比如在 a 方法中调用了 b 和 c 方法
     * 如果这拦截器拦截了a方法,那么这个beanMethod就是a方法,同理,拦截了b ,beanMethod就是b方法
     * 解决方法:维护了一个ThreadLocal的变量,在方法第一调用时,会将这个方法放入的变量中
     * 比如 先调用了a方法,那么调用b方法的时候,就会去比较 a 和 b 方法,发现方法不一致
     * 那么就会去容器找这个beanName 对应的bean对象,如果存在这个bean对象,就直接返回这个bean对象,没有就回去创建这个bean对象,并将它放入容器
     * 如果调用的是当前方法,那么就直接调用父类(真正的配置类对象)的方法
     */
    if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
        // create the bean instance.
        // 当前执行的方法和调用的方法是同一个方法,直接调用父类的方法进行对象的创建,并返回
        return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
    }
    // 不是同一个方法,就调用 $$beanFactory 去容器中获取对应的对象
    return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

对FactoryBean对象的代理

private Object enhanceFactoryBean(final Object factoryBean, Class<?> exposedType,
                final ConfigurableBeanFactory beanFactory, final String beanName) {
    Class<?> clazz = factoryBean.getClass();
    boolean finalClass = Modifier.isFinal(clazz.getModifiers());
    boolean finalMethod = Modifier.isFinal(clazz.getMethod("getObject").getModifiers());
    if (finalClass || finalMethod) {
        // final方法或者final类  尝试使用JDK的动态代理
        if (exposedType.isInterface()) {
            // 存在接口,通过接口使用jdk的动态代理,返回代理对象
            // 在代理对象会对 getObject 方法进行拦截,从容器中找这个beanName,如果存在就返回
            // 不存在就执行目标方法进行创建,beanName 不带有 & 符号的
            return createInterfaceProxyForFactoryBean(factoryBean, exposedType, beanFactory, beanName);
        }else{
            // final类型的没有接口就不能代理
            // 直接返回这个 factoryBean 对象(从容器中通过 &beanName 获取的对象)
            return factoryBean;
        }
    }
    // 返回cglib代理的对象 同样时拦截 getObject 方法,添加了一个处理器
    // 和使用jdk代理相同的逻辑,
    return createCglibProxyForFactoryBean(factoryBean, beanFactory, beanName);
}

JDK的动态代理

private Object createInterfaceProxyForFactoryBean(final Object factoryBean, Class<?> interfaceType,final ConfigurableBeanFactory beanFactory, final String beanName) {
    return Proxy.newProxyInstance(
        factoryBean.getClass().getClassLoader(), new Class<?>[] {interfaceType},
        (proxy, method, args) -> {
            if (method.getName().equals("getObject") && args == null) {
                // 直接从容器中获取真正的对象
                return beanFactory.getBean(beanName);
            }
            return ReflectionUtils.invokeMethod(method, factoryBean, args);
        });
}

CGLib代理

private Object createCglibProxyForFactoryBean(final Object factoryBean,final ConfigurableBeanFactory beanFactory, final String beanName) {
    // 同样时拦截 getObject 方法
    ((Factory) fbProxy).setCallback(0, (MethodInterceptor) (obj, method, args, proxy) -> {
        if (method.getName().equals("getObject") && args.length == 0) {
            return beanFactory.getBean(beanName);
        }
        return proxy.invoke(factoryBean, args);
    });
    return fbProxy;
}

EventListenerMethodProcessor

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    this.beanFactory = beanFactory;

    Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
    List<EventListenerFactory> factories = new ArrayList<>(beans.values());
    AnnotationAwareOrderComparator.sort(factories);
    this.eventListenerFactories = factories;
}

获取容器中所有的EventListenerFactory,并缓存在eventListenerFactories集合中。这里与Spring的事件监听机制有关,后续补充...

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

推荐阅读更多精彩内容