Spring之BeanPostProcessor

04-27 1646阅读 0评论

1.什么是BeanPostProcessor

BeanPostProcessor是bean的后置处理器,会影响bean的一些行为甚至是替换原有的bean。了解BeanPostProcessor之前最好有对BeanFactoryPostProcessor有一些了解,不了解的小伙伴可以查看我的上篇博文Spring之BeanFactoryPostProcessor

2.BeanPostProcessor是在什么时机注入到Spring中的

BeanPostProcessor从本质上讲也是一个bean,它早于其他普通bean之前实例化,然后作用于其他普通bean,我们看一下Spring源码中实例化时机

具体源码在AbstractApplicationContext#refresh方法中

Spring之BeanPostProcessor

我们可以看到BeanPostProcessor早于普通bean的实例化时机,所以可以对普通bean进行处理,后文我将BeanPostProcessor简称为bpp

这个registerBeanPostProcessors对bpp的处理,和Spring对bfpp的处理很像,我在这里贴一下之前整理的处理顺序Spring之BeanPostProcessor

3.BeanPostProcessor一些方法对bean的影响

1.InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation

我们看一下AbstractAutowireCapableBeanFactory#createBean方法

Spring之BeanPostProcessor

我们看一下注释:给bpp一个机会返回一个代理的对象,这很显然是一个扩展点,我们点进去看看究竟

Spring之BeanPostProcessor

我们看到只要我们完成这三个条件,就不用执行后面的实例化流程了,比如说填充属性的方法(populateBean),各种回调方法,比如ApplicationContextAware, InitializingBean

我们来自定义一个bpp,来满足上述条件,看看结果是否符合预期

创建一个普通的类,标记上@Component注解,会被扫描生成bd对象

package com.test.spring.model;
import org.springframework.stereotype.Component;
@Component
public class ModelJ {
}

创建一个实现ApplicationContextAware接口和使用@Autowired注入属性的类

package com.test.spring.model;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ModelI implements ApplicationContextAware {
    @Autowired
    private ModelJ modelJ;
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

创建一个配置类

package com.test.spring.config;
import org.springframework.context.annotation.ComponentScan;
/**
 * 这里可以不用加@Configuration
 * AnnotationConfigApplicationContext会将构造方法注入的类,解析成bd
 */
@ComponentScan("com.test.spring")
public class AppConfig {
}
创建一个bfpp,修改其beforeInstantiationResolved属性(满足第一条件)
@Component
public class SeventhBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        if (registry.containsBeanDefinition("modelI")) {
            // 这里是ScannedGenericBeanDefinition 还不能强转成RootBeanDefinition
            ScannedGenericBeanDefinition scannedGenericBeanDefinition = (ScannedGenericBeanDefinition) registry.getBeanDefinition("modelI");
            RootBeanDefinition beanDefinition = new RootBeanDefinition();
            beanDefinition.setBeanClassName(scannedGenericBeanDefinition.getBeanClassName());
            try {
                // 这个属性是包可见,利用反射强行设置了一下
                Field beforeInstantiationResolved = beanDefinition.getClass().getDeclaredField("beforeInstantiationResolved");
                beforeInstantiationResolved.setAccessible(true);
                beforeInstantiationResolved.set(beanDefinition, true);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            registry.registerBeanDefinition("modelI", beanDefinition);
        }
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    }
}

创建一个bpp 指定其postProcessBeforeInstantiation方法返回值(满足第二条件),postProcessAfterInitialization就直接使用父类方法,返回原对象(满足第三条件)

package com.test.spring.bpp;
import com.test.spring.model.ModelI;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class FirstBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class beanClass, String beanName) {
        if (beanClass == ModelI.class) {
            try {
                ModelI modelI = (ModelI) beanClass.newInstance();
                return modelI;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            return SmartInstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
        }
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 这个父类方法就是返回原对象,直接使用父类方法
        return SmartInstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

运行main方法 查看结果Spring之BeanPostProcessor我们可以看到属性注入方法(populateBean)和回调方法(setApplicationContext)都没有执行,Spring处理完bpp的postProcessAfterInitialization方法,就直接返回了

2. MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition

这个类我们拿其子类AutowiredAnnotationBeanPostProcessor举例

AutowiredAnnotationBeanPostProcessor主要是查找所有bean中的注入点,后面在某个时间点将查找的注入点注入到bean中

我们看一下Spring源码怎么定义注入点

Spring之BeanPostProcessor

简单来说就是方法或者属性上面加了@Autowired注解就是注入点后期会在某个时间点注入,我们写个简单的例子来看一下

创建一个类ModelK

package com.test.spring.model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ModelK {
    @Autowired
    private ModelI modelI;
    private ModelJ modelJ;
    @Autowired
    public void setModelJ(ModelJ modelJ) {
        this.modelJ = modelJ;
    }
}

运行main方法 查看结果

Spring之BeanPostProcessor注入点都注入到bean中了

3.InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation

这个类在populateBean方法中,如果方法返回false就表示这个bean 不填充properties了

Spring之BeanPostProcessor

我们写一个简单例子看一下

创建一个类ModelL

package com.test.spring.model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ModelL {
    @Autowired
    private ModelJ modelJ;
}

创建一个bpp

package com.test.spring.bpp;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class SecondBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if ("modelL".equals(beanName)) {
            return false;
        } else {
            return SmartInstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
        }
    }
}

运行main方法 查看结果

Spring之BeanPostProcessor

属性modelJ忽略注入了

4.BeanPostProcessor#postProcessBeforeInitialization

这个方法前后一般执行了钩子函数 罗列一下

在这个方法之前

AbstractAutowireCapableBeanFactory#invokeAwareMethods

  1. setBeanName
  2. setBeanClassLoader
  3. setBeanFactory

相关子类实现

InitDestroyAnnotationBeanPostProcessor$LifecycleElement

  1. 处理@PostConstruct标注的方法

ApplicationContextAwareProcessor

  1. setEnvironment
  2. setEmbeddedValueResolver
  3. setResourceLoader
  4. setApplicationEventPublisher
  5. setMessageSource
  6. setApplicationStartup
  7. setApplicationContext

在这个方法之后

AbstractAutowireCapableBeanFactory#invokeInitMethods

  1. 处理实现InitializingBean接口的bean
5.BeanPostProcessor#postProcessAfterInitialization

@EnableTransactionManagement注解我们经常使用,应该会很熟悉,其实它的原理就是注入了一个bfpp(AbstractAutoProxyCreator的一个子类,但是子类没有重写postProcessAfterInitialization方法,所以相关逻辑还是在AbstractAutoProxyCreator类中),这个bfpp的重要作用就是动态代理,我们来看相关代码

Spring之BeanPostProcessor

总结

bpp的作用很强大,但是也很危险,如果不加条件判断要处理的特定bean,所有的bean的都会受影响,所有的bean的都会受影响,所有的bean的都会受影响,重要的事情说三遍。而且这种错误很不容易发现,必须在一个个bpp中debug,所以使用前要做到谨慎再谨慎


免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,1646人围观)

还没有评论,来说两句吧...

目录[+]