zoukankan      html  css  js  c++  java
  • 04Spring_bean 后处理器(后处理Bean),BeanPostProcessor ,bean创建时序,动态代理

    这篇文章很重要,讲解的是动态代理,以及bean创建前后的所发生的事情。介绍一个接口:在Spring构造Bean对象过程中,有一个环节对Bean对象进行 后处理操作 (钩子函数) ----- Spring 提供 BeanPostProcessor 接口。我们可以自定义类,实现 BeanPostProcessor 接口,配置到Spring容器中,在构造对象时,spring容器会调用接口中方法。

    这个接口两个方法public Object postProcessAfterInitialization(Object bean, String beanName) 方法以及public Object postProcessBeforeInitialization(final Object bean, String beanName) 这两个方法里面的bean就是spring IO容器创建对象,beanName就是Sring配置文件applicationContext.xml文件里面对应的bean id。

    为了说明postProcessBeforeInitialization和postProcessAfterInitialization的具体调用顺序,举一个例子说明。

    //applicationContext.xml
    <bean id="teacherService" class="cn.csdn.cyclelife.TeacherService"  init-method="init" destroy-method="destroy">
     <constructor-arg type="java.lang.Integer" index="0">
     <value>20</value>
      </constructor-arg>
     <property name="name">
     <value>Longmanfei</value>
     </property>
     </bean>
    <bean id="postService"class="cn.csdn.cyclelife.PostService"></bean>
    //TeacherService bean
    public class TeacherService {
    
        private String name;
     
        private Integer age;
    	
    	
    	public void setName(String name){
    		System.out.println("----这是teacherservice的set方法----");
    		this.name=name;
    	}
    	
    	public TeacherService(Integer age){
    		this.age=age;
    	}
    	
    
    	public void init(){
    		System.out.println("--------这是teacherservice的init的方法-------------");
    	}
    	
    	public void destroy(){
    		System.out.println("---------这是销毁(destroy)方法----------");
    	}
    	
    	public void display(){
    		System.out.println(this.name+"-----------------"+this.age);
    	}
     }
    // 实现接口的BeanPostProcessor bean 
     public class PostService implements BeanPostProcessor{
    
    	
    	/**在初始化之后调用这个方法*/
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String arg1)
    			throws BeansException {
    		System.out.println("----这是init之后执行的方法postProcessAfterInitialization----");
    		return bean;
    	}
    
    	/**在初始bean之前调用的这个方法 在init方法之前执行,在set方法之后*/
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String arg1)
    			throws BeansException {
    		/**instanceof 判断前者是否是后者的一个实例*/
    		if(bean instanceof TeacherService){
    			System.out.println("--这是在init之前进行修改bean的属性值--");
    			/*这里我们不能直接new一个对象 因为bean本身就是一个对象,直接转换就可以了*/
    			((TeacherService)bean).setName("Longmanfei");
    		}
    	    System.out.println("---这是init之前执行的方法postProcessBeforeInitialization---");
    		return bean;
    	}
    }
    //Junit 测试方法
    public class App {
    	
    	
    	@Test
    	public void test1(){
    		/**加载容器*/
    		ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"applic*.xml"});
    		/**调用getbean方法*/
    		TeacherService ts = (TeacherService) ac.getBean("teacherService");
    		
    		
    		ts.display();
    		
    		/**调用close方法关闭bean*/
    		AbstractApplicationContext aac =(AbstractApplicationContext) ac;
    		aac.close();
    	}
    
    }
    //这是执行结果(当加载容器的时候会判断是否有实现接口的BeanPostProcessor bean,如果有其他Bean就会按照特定的顺序去执行,并且执行实现接口的bean里的方法)
    ----这是teacherservice的set方法----
    --这是在init之前进行修改bean的属性值--
    ----这是teacherservice的set方法----
    ---这是init之前执行的方法postProcessBeforeInitialization---
    --------这是teacherservice的init的方法-------------
    ----这是init之后执行的方法postProcessAfterInitialization----
    Longmanfei-----------------20
    ---------这是销毁(destroy)方法----------
    

    这个例子里面可以看到Spring先会创造bean的实例对象,然后调用postProcessBeforeInitialization,然后再调用init-method="init"方法,然后再调用postProcessAfterInitialization方法。

    这里我给一个bean的创建流程图

    这个图对上面的例子的代码运行结果给出了很好的解释。(这个博客非常不错http://uule.iteye.com/blog/2094609)

    换句话说我们在执行public Object postProcessBeforeInitialization(final Object bean, String beanName)方法时,传入的值bean就是IOC容器已经给我们创建好的对象了,

    那么我们可以拿这个对象做什么呢?很重要的一点就是动态代理,我们可以给这个bean对象做个动态代理。

    先给出具体代码我在做分析:

    做动态代理必须要接口,所以我先给出抽象角色(接口)

    package cn.itcast.spring.d_lifecycle;
    
    public interface IHello {
        public void sayHello();
    
        public void setup();
    
        public void teardown();
    }

    再给出真实角色:

    package cn.itcast.spring.d_lifecycle;
    
    /**
     * Bean对象,初始化和销毁方法 (无返回值、无参数、非静态)
     * 
     * @author seawind
     * 
     */
    public class LifeCycleBean implements IHello {
        public LifeCycleBean() {
            System.out.println("LifeCycleBean 构造...");
        }
    //配置文件中init-method="setup"
        public void setup() {
            System.out.println("LifeCycleBean 初始化...");
        }
    //配置文件中destroy-method="teardown"
    public void teardown() {
    System.out.println(
    "LifeCycleBean 销毁...");
    }
    //被代理的方法
    @Override
    public void sayHello()
    {

    System.out.println(
    "hello ,itcast...");

    }
    }

    再给出实现了BeanPostProcessor接口的方法:

    package cn.itcast.spring.d_lifecycle;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    /**
     * 后处理器
     * 
     * @author seawind
     * 
     */
    public class MyBeanPostProcessor implements BeanPostProcessor {
        static int a=0;
        @Override
        /**
         * bean 代表Spring容器创建对象
         * beanName 代表配置对象对应 id属性
         */
        
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (beanName.equals("lifeCycleBean")) {
                System.out.println("后处理器 初始化后执行...");
            }
            return bean;
        }
    
        @Override
        public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
            // 针对bean id 为 lifeCycleBean的对象 进行代理,配置文件中bean的id为lifeCycleBean就做一下处理
            if (beanName.equals("lifeCycleBean")) {
                System.out.println("后处理器 初始化前执行...");
    /*给传进来的bean对象做一个动态代理.bean.getClass().getClassLoader表示要被执行代理的类,也就是我们的IOC容器创建的bean对象。
    bean.getClass().getInterfaces()表示我们的要代理的类所实现
    的所有的而接口,我们最后new出来的代理类会按照这个参数实现这些所有的接口。这也是为什么动态代理模式必须要用接口的原因了。
    new InvocationHandler() {}表示真正要执行的方法。
    最后用的是return 就是把生成出来的的代理类返回了。所以执行好这个方法后其实的返回的是new 出来的的代理类,而不是之前的bean对象了。(这句话非常重要)
    */
    return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //模拟代理方法(额外要执行的方法)
    System.out.println("执行代理.....");
    //执行要真正的方法 return method.invoke(bean, args); } }); }
    return bean; } }

    再给出Spring的配置文件(applicationContext.xml)

    <bean id="lifeCycleBean" class="cn.itcast.spring.d_lifecycle.LifeCycleBean" 
            init-method="setup" destroy-method="teardown" />

    最后给出Junit的测试代码

    package cn.itcast.spring.d_lifecycle;
    
    import org.junit.Test;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class LifeCycleTest {
        @Test
        public void testInitDestroy() {
            ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            IHello lifeCycleBean = (IHello) applicationContext.getBean("lifeCycleBean");
            System.out.println(lifeCycleBean);
            lifeCycleBean.sayHello();
    
            // 必须手动调用 容器销毁的方法 --- web服务器tomcat,自动调用容器销毁
            applicationContext.close();
        }
    }

    对上面代码的分析:经过public class MyBeanPostProcessor implements BeanPostProcessor里面的postProcessBeforeInitialization方法后,就是给IOC创建的bean对象进行了动态代理,在Junit的测试代码中。我们执行了 lifeCycleBean.sayHello();就会被动态代理给拦截,执行 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {......}里面的方法.这里的lifeCycleBean已经不是lifeCycleBean.class类型了,而是com.sun.proxy.$Proxy4类型了,要验证这个观点很简单,只要在public class LifeCycleTest 方法中的 lifeCycleBean.sayHello();之前加一句System.out.println(lifeCycleBean);就可以得到验证。

    最后给出上述代码的是运行结果:

    后处理器 初始化前执行...
    执行代理.....
    被代理的方法是public abstract void cn.itcast.spring.d_lifecycle.IHello.setup()a的值是1aaaaacn.itcast.spring.d_lifecycle.LifeCycleBeanLifeCycleBean 初始化...
    后处理器 初始化后执行...
    执行代理.....
    被代理的方法是public java.lang.String  java.lang.Object.toString()

    aaaaacn.itcast.spring.d_lifecycle.LifeCycleBeancn.itcast.spring.d_lifecycle.LifeCycleBean@a0430b6
    测试方法中lifeCycleBean的真相是com.sun.proxy.$Proxy4执行代理.....

    被代理的方法是public abstract void cn.itcast.spring.d_lifecycle.IHello.sayHello()a的值是3aaaaacn.itcast.spring.d_lifecycle.LifeCycleBeanhello ,itcast...

    这里很奇怪,为什么执行了这么多的“执行代理” 原因很简单,因为setup() System.out.println(lifeCycleBean)和 lifeCycleBean.sayHello();每一次执行方法时都会被动态代理所拦截,从而执行了三次动态代理。

  • 相关阅读:
    js事件委托篇(附js一般写法和js、jq事件委托写法)
    markdown工作随笔总结
    论实际开发中按钮显示和隐藏自身或其他元素
    彻底理解行内元素和块级元素,不必硬背
    redis搭建主从配置
    [Python图像处理]三.获取图像属性及通道处理
    [Python图像处理]二 OpenCV借助Numpy库读取和修改像素
    [Python图像处理]一.图像处理基础知识及OpenCV入门函数
    opencv2图像处理--灰度变换
    提取新闻网站信息
  • 原文地址:https://www.cnblogs.com/shenxiaoquan/p/5705975.html
Copyright © 2011-2022 走看看