美文网首页
BeanPostProcessor的使用和源码解析

BeanPostProcessor的使用和源码解析

作者: 小陈阿飞 | 来源:发表于2018-11-26 15:08 被阅读2次

    BeanPostProcessor接口作用:

    如果我们想在Spring容器中完成bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理。我们需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。

    /**
     * bean后置处理器
     * @author zss
     *
     */
    public class PostProcessor implements BeanPostProcessor {
    
        @Override
        public Object postProcessBeforeInitialization(Object bean,
                String beanName) throws BeansException {
            if ("narCodeService".equals(beanName)) {//过滤掉bean实例ID为narCodeService
                return bean;
            }
            System.out.println("后置处理器处理bean=【"+beanName+"】开始");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean,
                String beanName) throws BeansException {
            if ("narCodeService".equals(beanName)) {
                return bean;
            }
            System.out.println("后置处理器处理bean=【"+beanName+"】完毕!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return bean;
        }
    
    }
    注意:接口中两个方法不能返回null,如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
         因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    

    将Spring的后置处理器PostProcessor配置到Spring配置文件中

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- 定义一个bean -->
         <bean id="narCodeService" class="com.test.service.impl.NarCodeServiceImpl">
         </bean>
        <bean id="beanLifecycle" class="com.test.spring.BeanLifecycle" init-method="init" destroy-method="close">
            <property name="name" value="张三"></property>
            <property name="sex" value="男"></property>
        </bean>
    
        <!-- Spring后置处理器 -->
        <bean id="postProcessor" class="com.test.spring.PostProcessor"/>
    </beans>
    

    源码分析:

    @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);
    
                    // 在这里把所有实现了BeanPostProcessor接口注册到容器的beanPostProcessors里面
                    registerBeanPostProcessors(beanFactory);
    
    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()) {
                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和applyBeanPostProcessorsAfterInitialization的具体代码分别为:

    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
    
            Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
                result = beanProcessor.postProcessBeforeInitialization(result, beanName); if (result == null) { return result;
                }
            } return result;
        }
    
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
    
            Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
                result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) { return result;
                }
            } return result;
        }
    

    根据以上代码,我们得知,在invokeInitMethods的执行前后,spring会分别调用所有的BeanPostProcessor,执行其中的方法,那么invokeInitMethods的具体内容我们仍需要看下,发现此方法主要作用有两个:1、判断bean是否继承了InitializingBean,如果继承接口,执行afterPropertiesSet()方法,2、获得是否设置了init-method属性,如果设置了,就执行设置的方法

    protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) {
                    logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
                } if (System.getSecurityManager() != null) { try {
                        AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                            @Override public Object run() throws Exception {
                                ((InitializingBean) bean).afterPropertiesSet(); return null;
                            }
                        }, getAccessControlContext());
                    } catch (PrivilegedActionException pae) { throw pae.getException();
                    }
                } else {
                    ((InitializingBean) bean).afterPropertiesSet();
                }
            } if (mbd != null) {
                String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                        !mbd.isExternallyManagedInitMethod(initMethodName)) {
                    invokeCustomInitMethod(beanName, bean, mbd);
                }
            }
        }
    

    根据以上描述,我们可以看到原有推断有一些问题,两个方法的执行主要是在bean完成初始化之后,准备执行默认方法时候对bean进行包装。

    三、应用场景

    几个典型的应用如:

    1、解析bean的注解,将注解中的字段转化为属性

    2、统一将属性在执行前,注入bean中,如数据库访问的sqlMap,如严重服务,这样不需要每个bean都配置属性

    3、打印日志,记录时间等。

    相关文章

      网友评论

          本文标题:BeanPostProcessor的使用和源码解析

          本文链接:https://www.haomeiwen.com/subject/lujbqqtx.html