Spring 的 BeanPostProcessor 原理剖析及使用


一、接口介绍

        spring提供了一个接口类 BeanPostProcessor,我们称其为后置处理器,作用是在 bean 的实例化的过程中对 bean 进行自定义的包装处理,其提供了两个方法。先看看 BeanPostProcessor 的定义。

public interface BeanPostProcessor{ 

        public abstract Object postProcessBeforeInitialization(Object obj, String s) throws BeansException; 

          public abstract Object postProcessAfterInitialization(Object obj, String s) throws BeansException;  

}

        根据类的名称,我们可以猜测两个接口方法执行的位置:

        1、在bean初始化之前执行;

   2、在bean的初始化之后执行。

二、源码解析

        理解其原理以及执行的位置,需要到源码中寻找答案。跟踪创建 bean 的实例的 getBean 方法,层层跟进,在AbstractAutowireCapableBeanFactory 类中,找到了执行方法:

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {

        if (System.getSecurityManager() != null) { 

                AccessController.doPrivileged(new PrivilegedAction() { 

                        @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;

}       

        如上加粗部分是主要的代码,invokeAwareMethods(beanName, bean)、 applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);invokeInitMethods(beanName, wrappedBean, mbd)、invokeInitMethods(beanName, wrappedBean, mbd)、applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)。

        1、invokeAwareMethods(beanName, bean),对实现了 aware 接口的 bean 进行特殊的处理,实现aware 接口的 bean 在被初始化后,可以取得一些相对应的资源。比如, applicationAware , beanFactoryAware 等。

        2applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)后置处理器初始化前方法调用。

        3、invokeInitMethods(beanName, wrappedBean, mbd),用于用户初始化方法的调用,如实现了 InitializingBean 接口的 bean ,调用其 afterPropertiesSet 和 用户配置的 init-method 方法的调用。

        进入applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)和applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName),查看其源码:

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;

}

三、使用

1、定义接口和实例 

publi interface DemoService {

    public void sayHello();

}

public interface NameInit { 

     public void setName(String name);  

}

public class DemoServiceImpl implements DemoService,NameInit {

        String name; 

        @Override 

        public void sayHello() { 

                System.out.println("hello "+name); 

        }     

        @Override      

        public void setName(String name) {  

                this.name=name;    

        }

}

2、定义bean的配置

3、定义一个BeanPostProcessor 实例

        凡是继承了NameInit的接口,均实例化,注入name值。此处定义接口一方面是要使用接口中提供的setName方法,另一方面减轻系统压力,防止每个bean都进行注入。

public class NameBeanPostProcessor implements BeanPostProcessor { 

        String name;

        public String getName() { 

                return name;

         } 

        public void setName(String name) { 

                this.name = name; 

        } 

        @Override         

        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 

                if(bean instanceof NameInit){ 

                    ((NameInit)bean).setName(name);

                  }  

                return bean; 

        }      

        @Override 

        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  

                return bean;    

        }

 }  

5、定义bean,注入name的值

          

6、定义另一个BeanPostProcessor ,仅打印日志

public class LogBeanPostProcessor implements BeanPostProcessor { 

        @Override                    

         public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 

                System.out.println("正在处理"+beanName); return bean;  

        } 

        @Override      

        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 

                System.out.println("已经处理完成"+beanName);   

                 return bean;

         }   

 } 

7、定义bean

8、测试类

public class BeanPostProcessorTest { 

        public static void main(String[] args) { 

                ApplicationContext context=new FileSystemXmlApplicationContext("beanpostprocessor.xml"); 

                DemoService demoService=(DemoService) context.getBean("demoService"); 

                demoService.sayHello();

         }       

}

9、测试结果

正在处理demoService 

已经处理完成demoService 

hello zhangsan 

10、总结

  两个方法均在bean实例化期间已经完成;

     name属性是根据NameInit接口自动注入;

  由于两个方法执行的时间特殊性,所以打印日志和记录时间意义不大,主要还是用于注入属性和完善配置。

你可能感兴趣的:(Spring 的 BeanPostProcessor 原理剖析及使用)