• BeanPostProcessor详解


    转自: https://www.jianshu.com/p/d26e8ec9c077?

    BeanPostProcessor也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初始化前后)会回调BeanPostProcessor中定义的两个方法。BeanPostProcessor的源码如下

    public interface BeanPostProcessor {
    
    
        Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    
        
        Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    
    }
    

    其中postProcessBeforeInitialization方法会在每一个bean对象的初始化方法调用之前回调;postProcessAfterInitialization方法会在每个bean对象的初始化方法调用之后被回调。具体执行时期可以参考Spring中Bean的生命周期源码探究

    自定义BeanPostProcessor

    查看BeanPostProcessor源码,可以看到它两个方法的参数都相同,其中第一个参数Object bean表示当前正在初始化的bean对象。此外两个方法都返回Object类型的实例,返回值既可以是将入参Object bean原封不动的返回出去,也可以对当前bean进行包装再返回。来看看下面的自定义BeanPostProcessor

    /**
     * 后置处理器:初始化前后进行处理工作
     * 需要将后置处理器加入到容器中
     */
    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("postProcessBeforeInitialization..."+beanName+"..."+bean);
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("postProcessAfterInitialization..."+beanName+"..."+bean);
            return bean;
        }
    
    }
    

    Spring容器中加入MyBeanPostProcessor之后,针对容器中每个创建的Bean对象(Spring自身创建的Bean和应用程序创建的Bean),都会回调postProcessBeforeInitializationpostProcessAfterInitialization方法。

    执行原理

    BeanPostProcessor的执行是定义在容器的刷新过程中,容器刷新对象具体的方法为:AbstractApplicationContext.refresh()
    在refresh方法执行的调用栈中会去调用AbstractAutowireCapableBeanFactory.doCreateBean()方法,该方法节选源码如下

    protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }
        
        invokeInitMethods(beanName, wrappedBean, mbd);
    
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }
    

    看到在调用初始化方法前后会分别调用applyBeanPostProcessorsBeforeInitialization()applyBeanPostProcessorsAfterInitialization()applyBeanPostProcessorsBeforeInitialization()方法的源码如下

    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {
    
        Object result = existingBean;
        //获取所有的BeanPostProcessor进行遍历
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
            if (result == null) {
                return result;
            }
        }
        return result;
    }
    

    可以看到其逻辑为遍历得到容器中所有的BeanPostProcessor,然后一次执行postProcessBeforeInitialization,一但返回null,就跳出for循环不执行后面的BeanPostProcessor.postProcessorsBeforeInitialization()。也就是说如果返回的是null那么我们通过getBean方法将得不到目标Bean。
    applyBeanPostProcessorsBeforeInitialization()方法的逻辑和上面一致,就是将循环执行的beanProcessor.postProcessBeforeInitialization()替换成beanProcessor.postProcessAfterInitialization()
    Spring底层的很多功能特性都是借助BeanPostProcessor的子类来实现。

    常见BeanPostProcessor分析

    下图是debug过程中,ApplicationContext对象中的包含的BeanPostProcessor。具体包含哪些BeanPostProcessor和具体应用程序相关,除了下标3中的MyBeanPostProcessor为自定义的BeanPostProcessor,其余均为Spring自带的BeanPostProcessor。

     


    下面来分析一下ApplicationContextAwareProcessorAutowiredAnnotationProcessor的执行原理。

    ApplicationContextAwareProcessor

    ApplicationContextAwareProcessor后置处理器的作用是,当应用程序定义的Bean实现ApplicationContextAware接口时注入ApplicationContext对象。

    @Component
    public class Car implements ApplicationContextAware {
    
        private ApplicationContext applicationContext;
    
        public Car(){
            System.out.println("car instance...");
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            System.out.println("ApplicationContextAware...setApplicationContext()");
            this.applicationContext = applicationContext;
        }
    }
    

    那Car是如何通过实现ApplicationContextAware接口就能获得ApplicationContext对象呢?答案是通过ApplicationContextAwareProcessor后置处理器来实现,我们来看看ApplicationContextAwareProcessor的源码

    class ApplicationContextAwareProcessor implements BeanPostProcessor {
    
        private final ConfigurableApplicationContext applicationContext;
    
        private final StringValueResolver embeddedValueResolver;
    
    
        /**
         * Create a new ApplicationContextAwareProcessor for the given context.
         */
        public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
            this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
        }
    
    
        @Override
        public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
            AccessControlContext acc = null;
            // 这里bean是Car,它实现了ApplicationContextAware接口
            if (System.getSecurityManager() != null &&
                    (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                            bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                            bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
                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) {
                    // 会执行这里回调car重写的setApplicationContext方法,然后将this.applicationContext注入给Car
                    ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
                }
            }
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) {
            return bean;
        }
    
    }
    

    InitDestroyAnnotationBeanPostProcessor

    InitDestroyAnnotationBeanPostProcessor后置处理器是用来处理自定义的初始化方法和销毁方法。Spring中提供了3种自定义初始化和销毁方法:

    1. 通过@Bean指定init-method和destroy-method属性
    2. Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);
    3. @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法@PreDestroy:在容器销毁bean之前通知我们进行清理工作

    InitDestroyAnnotationBeanPostProcessor的作用就是让第3种方式生效。先看看如何使用@PostConstruct@PreDestroy注解。

    @Component
    public class Car {
    
        public Car(){
            System.out.println("car instance...");
        }
    
        /**
         * 自定义的初始化方法
         */
        @PostConstruct
        public void init(){
            System.out.println("car ... init...");
        }
    
        /**
         * 自定义的销毁方法
         */
        @PreDestroy
        public void detory(){
            System.out.println("car ... detory...");
        }
    }
    

    InitDestroyAnnotationBeanPostProcessor会在Bean创建的时候通过反射的方式查找包含@PostConstruct@PreDestroy注解的方法,然后再通过反射执行方法。我们来看看InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization()的源码

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 获取bean的metadata
        LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
        try {
            // 执行@PostConstruct指定的init方法
            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;
    }
    

    metadata中已经解析出initMethods和destroyMethods,其具体内容如下。

     


    metadata.invokeInitMethods(bean, beanName);就是根据反射执行init方法。

    InstantiationAwareBeanPostProcessor

    InstantiationAwareBeanPostProcessorBeanPostProcessor的子接口。

    public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    
        //实例化Bean之前调用
        Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
    
        //实例化Bean之后调用
        boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
    
        //设置Bean对象中的某个属性时调用
        PropertyValues postProcessPropertyValues(
                PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
    
    }
    

    这两个接口的功能基本类似,不过要注意InstantiationAwareBeanPostProcessorBeanPostProcessor的方法名区别。InstantiationAwareBeanPostProcessor中是Instantiation, 而BeanPostProcessor是Initialization。

  • 相关阅读:
    Initializing port 0 ... Creating queues: nb_rxq=2 nb_txq=4... Ethdev port_id=0 invalid rss_hf: 0x3afbc, valid value: 0x38f3c
    docker mount
    人工智能能力提升指导总结
    一万字详解 Redis Cluster Gossip 协议
    SQL server函数转Oracle问题之一,强行使用临时表
    2020全球C++及系统软件技术大会成功落下帷幕
    PostgreSQL批量update与oracle差异
    逆向工程,调试Hello World !程序(更新中)
    “TensorFlow 开发者出道计划”全攻略,玩转社区看这里!
    SQL练习题一(逐行累计)
  • 原文地址:https://www.cnblogs.com/qin1993/p/11684633.html
Copyright © 2020-2023  润新知