zoukankan      html  css  js  c++  java
  • Spring中的后置处理器BeanPostProcessor讲解

    Spring中提供了很多PostProcessor供开发者进行拓展,例如:BeanPostProcessor、BeanFactoryPostProcessor、BeanValidationPostProcessor等一系列后处理器。他们的使用方式大多类似,了解其中一个并掌握他的使用方式,其他的可以触类旁通。

    BeanPostProcessor接口作用:

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

    BeanPostProcessor API:

    public interface BeanPostProcessor {  
      
        /** 
         * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean 
         * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} 
         * or a custom init-method). The bean will already be populated with property values.    
         */  
        //实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务  
        Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;  
      
          
        /** 
         * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean 
         * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}   
         * or a custom init-method). The bean will already be populated with property values.       
         */  
        //实例化、依赖注入、初始化完毕时执行  
        Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;  
      
    }

    BeanPostProcessor接口提供了两个供开发者自定义的方法:postProcessBeforeInitialization、postProcessAfterInitialization。

    postProcessBeforeInitialization:该方法主要针对spring在bean初始化时调用初始化方法前进行自定义处理。

    postProcessAfterInitialization:该方法主要针对spring在bean初始化时调用初始化方法后进行自定义处理。

    测试代码:

    com.test.model.Cat:

    package com.test.model;
    
    /**
     * 测试bean
     */
    public class Cat {
      private String name;
      private int age;
      
      public void say() {
        System.out.println("name:" + name);
        System.out.println("age:" + age);
      }
     
      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;
      }
    }
    View Code

    spring容器中配置cat,和cat的beanPostProcessor:

    <!--配置bean并初始化-->
        <bean id="cat" class="com.test.model.Cat" >
          <property name="name" value="HelloKitty" />
          <property name="age" value="1" />
        </bean>
        <bean id="catBeanPostProcessor" class="com.test.postprocessor.CatBeanPostProcessor" />

    com.test.postprocessor.CatBeanPostProcessor:

    package com.test.postprocessor;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import com.test.model.Cat;
    
    /**
     * 自定义后处理器
     */
    public class CatBeanPostProcessor implements BeanPostProcessor{
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof Cat) {
                  //输出原始属性
                  Cat cat = (Cat) bean;
                  cat.say();
                  return bean;
                }
             return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof Cat) {
                  //修改属性值,并返回
                  Cat cat = (Cat) bean;
                  cat.setName("hello maomi");
                  cat.setAge(3);
                  return cat;
                }
             return bean;
        }
        
    }

    IndexController:

    package com.cy.controller;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.context.support.WebApplicationContextUtils;
    
    import com.test.model.Cat;
    
    @Controller
    public class IndexController {
        
        //到index首页
        @RequestMapping(value="index")
        public String index(HttpServletRequest request){
            /**
             * 访问index同时,从容器中获取已经被初始化之后处理过的cat,打印信息
             */
            ServletContext servletContext = request.getSession().getServletContext();
            ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(servletContext);
            Cat c = (Cat) ac.getBean("cat");
            c.say();
            
            return "index";
        }
    }

    观察结果:

    容器启动时,输出:

    name:HelloKitty
    age:1
    访问项目http://localhost:8080/demo/index,index链接时,输出:
    name:hello maomi
    age:3
     
    --------------------------------------------------------------------------------------------------------------------------
    可以看到通过后处理器处理过后的bean信息已经改变。最后,看看源码中如何调用自定义实现的。
    在初始化bean方法中:AbstractAutowireCapableBeanFactory.java
    /**
     * 初始化bean
     */
    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
      //省略部分无关代码
      Object wrappedBean = bean;
      //初始化前
      if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
      }
     
      try {
        //调用初始化方法初始化bean
        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;
    }
    //postProcessBeforeInitialization方法调用
    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
        throws BeansException {
     
      Object result = existingBean;
      for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        //调用自定义postProcessBeforeInitialization方法
        Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
          return result;
        }
        result = current;
      }
      return result;
    }
    //postProcessAfterInitialization方法调用
    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {
     
      Object result = existingBean;
      for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        //自定义postProcessAfterInitialization方法调用
        Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
          return result;
        }
        result = current;
      }
      return result;
    }
  • 相关阅读:
    Android开发进阶 -- 通用适配器 CommonAdapter
    如何巧妙地在基于 TCP Socket 的应用中实现用户注册功能?
    如何让基于.NET 2.0的应用在高版本的系统上运行?
    即时通信系统中实现全局系统通知,并与Web后台集成【附C#开源即时通讯系统(支持广域网)——QQ高仿版IM最新源码】
    即时通信系统中实现聊天消息加密,让通信更安全【低调赠送:C#开源即时通讯系统(支持广域网)——GGTalk4.5 最新源码】
    程序员的那些事儿 -- 高级程序员买衣服
    程序员的那些事儿 -- 皆大欢喜的加薪
    GGTalk即时通讯系统(支持广域网)终于有移动端了!(技术原理、实现、源码)
    如何做到在虚拟数据库和真实数据库之间自由切换?【低调赠送:QQ高仿版GG 4.4 最新源码】
    如何实现:录制视频聊天的全过程? 【低调赠送:QQ高仿版GG 4.3 最新源码】
  • 原文地址:https://www.cnblogs.com/tenWood/p/8542521.html
Copyright © 2011-2022 走看看