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

}       

        如上加粗部分是主要的代码,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的配置

<bean id="demoService" class="com.zjl.beanpostprocessor.DemoServiceImpl"> </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的值

<bean id="nameBeanPostProcessor" class="com.zjl.beanpostprocessor.NameBeanPostProcessor">

         <property name="name" value="zhangsan"></property>  

</bean>

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

<bean id="logBeanPostProcessor" class="com.zjl.beanpostprocessor.LogBeanPostProcessor"> </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接口自动注入;

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

猜你喜欢

转载自blog.csdn.net/weixin_33889665/article/details/87007980