zoukankan      html  css  js  c++  java
  • spring后置处理器BeanPostProcessor

    BeanPostProcessor的作用是在调用初始化方法的前后添加一些逻辑,这里初始化方法是指在配置文件中配置init-method,或者实现了InitializingBean接口的afterPropertiesSet方法,注意不包括@PostConstruct这种初始化方式。可以看源码AbstractAutowireCapableBeanFactory类中的invokeInitMethods方法。

    1.用法

    新建Student类

    package com.demo.spring.entity;
    
    import javax.annotation.PostConstruct;
    
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.stereotype.Component;
    
    /**
     * @author chenyk
     * @date 2018年5月8日
     */
    @Component("student")
    public class Student{
        private String name;
        private int age;
        
        private School school;
        
        
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public School getSchool() {
            return school;
        }
        public void setSchool(School school) {
            this.school = school;
        }
        
        
        public void init(){
            System.out.println("执行 init方法");
        }
    
    }

    创建实现了BeanPostProcessor接口的后置处理器StudentBeanPostProcessor

    package com.demo.spring.entity;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    /**
     * Bean后置处理器
     * @author chenyk
     * @date 2018年6月29日
     */
    
    //以下这两个方法不能返回null,否则在调用初始化方法时会报空指针异常;因为后置处理器从springIOC容器中取出bean实例后需要再把bean实例放回去 public class StudentBeanPostProcessor implements BeanPostProcessor{ /** * 在bean实例调用初始化方法之前调用 */ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("student")){ System.out.println("开始调用init方法"); } return bean; } /** * 在bean实例调用初始化方法之后调用 */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("student")){ System.out.println("init方法调用结束"); } return bean; } }

    在配置文件aop.xml中添加以下信息

    <bean id="student" class="com.demo.spring.entity.Student" init-method="init" >
            <property name="name" value="张三"></property>
    </bean>
    <!-- spring会自动检测实现了BeanPostProcessor接口的类,并将其注册为后置处理器 --> <bean id="studentBeanPostProcessor" class="com.demo.spring.entity.StudentBeanPostProcessor" />

    测试方法

    @Test
        public void testAop5(){
            ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("aop.xml");        
        }

    看下打印信息:

    开始调用init方法
    2018-07-02 13:58:47,519 DEBUG [AbstractAutowireCapableBeanFactory.java:1731] : Invoking init method 'init' on bean with name 'student'  //这一行信息,就是即将调用init-method方法的日志打印
    执行 init方法
    init方法调用结束

    需要注意的是,如果一个类实现了BeanPostProcessor接口,那么这个类就作用于所有的bean实例,我们可以在BeanPostProcessor接口的两个方法中添加自己的控制和逻辑;

    2.源码分析

    2.1 找到实现BeanPostProcessor接口的类,并将其注册为后置处理器,看源码

        @Override
        public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing.
                prepareRefresh();
    
                // Tell the subclass to refresh the internal bean factory.
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                prepareBeanFactory(beanFactory);
    
                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    invokeBeanFactoryPostProcessors(beanFactory);
              //发现注册bean后置处理器,在这个方法中进行 
                    // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    onRefresh();
    
                    // Check for listener beans and register them.
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    finishRefresh();
                }
    
                catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                    }
    
                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();
    
                    // Reset 'active' flag.
                    cancelRefresh(ex);
    
                    // Propagate exception to caller.
                    throw ex;
                }
    
                finally {
                    // Reset common introspection caches in Spring's core, since we
                    // might not ever need metadata for singleton beans anymore...
                    resetCommonCaches();
                }
            }
        }

    2.2 后置处理器生效的地方,进入AbstractAutowireCapableBeanFactory类中的initializeBean方法

        protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    @Override
                    public Object run() {
                        invokeAwareMethods(beanName, bean);
                        return null;
                    }
                }, getAccessControlContext());
            }
            else {
                invokeAwareMethods(beanName, bean);
            }
         
            Object wrappedBean = bean;
    //后置处理器的postProcessBeforeInitialization方法
    if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); }      //调用初始化方法有:init-method,实现了InitializingBean接口的方法  try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); }
    //后置处理器的postProcessAfterInitialization方法
    if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }

     3.最后,我们看下@PostConstruct执行的时间点。

    进入AbstractAutowireCapableBeanFactory类的initializeBean方法

    protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    @Override
                    public Object run() {
                        invokeAwareMethods(beanName, bean);
                        return null;
                    }
                }, getAccessControlContext());
            }
            else {
                invokeAwareMethods(beanName, bean);
            }
    
            Object wrappedBean = bean;
            if (mbd == null || !mbd.isSynthetic()) {
    //这个是后置处理器的方法,其实@PostConstruct是在CommonAnnotationBeanPostProcessor后置处理器的父类InitDestroyAnnotationBeanPostProcessor中实现的,
    //也就是说@PostConstruct是由后置处理器来处理实现的进入该方法 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; }

    进入applyBeanPostProcessorsBeforeInitialization方法

        public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
                throws BeansException {
    
            Object result = existingBean;
            for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
           //在循环中会发现一个类 CommonAnnotationBeanPostProcessor,然后进入其父类InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization该方法 进入该方法 result
    = beanProcessor.postProcessBeforeInitialization(result, beanName); if (result == null) { return result; } } return result; }

    进入postProcessBeforeinitialization方法

        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    //该类封装着一些通过注解的方式标识的初始化方法和销毁方法,以及相关属性 LifecycleMetadata metadata
    = findLifecycleMetadata(bean.getClass()); try {
    //@PostConstrutct注解就是在此处生效调用 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; }
  • 相关阅读:
    Activiti 整合的小插曲
    IDEA 提示找不到 javax 等 tomcat 的相关包
    一些好用的 Oracle 批处理和语句
    Oracle 日志报错导致的 “没有登录” 问题
    WebPack 从安装到闲置
    CHENEY-YANG'S BLOG(cheney-yang)
    Java基础知识常识总结
    激活Navicat
    IDEA文件头版权模板
    关于Spring框架中StringUtils常用/易误用方法解析
  • 原文地址:https://www.cnblogs.com/51life/p/9254505.html
Copyright © 2011-2022 走看看