• day38 09-Spring类的完整生命周期及后处理Bean


    可以配置Bean的这个类的初始化和销毁的方法。

    如何销毁这个bean?销毁必须得手动地关闭掉容器才行。而且销毁必须是在scope="singleton"下才有效。因为如果你scope="prototype"它就会生成N多的实例。它就不知道销毁哪个实例了。


    Bean的生命周期。在Spring创建这个Bean的过程中总共有11个步骤。

     所以Spring在生成Bean的生命周期的过程中总共有11个步骤。


     需求:假设我有N多个Service,都需要在add()方法之前作权限校验,那么N个add方法都需要做权限校验.你每个类都打开,每个add()方法之前都加上权限校验的代码。特别麻烦。如果说不想要了,还得50个类都打开全部去掉。特别麻烦。

    有了后处理bean之后可以把代码加在后处理bean上,不影响业务逻辑,不想要的时候最多在配置文件中把后处理bean去掉,想要的时候又在配置文件中把后处理bean加进来。


     Spring类完整的生命周期记不记住无所谓,关键是后处理bean上。 


    package cn.itcast.spring3.demo4;
    
    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;
    
    
    public class MyBeanPostProcessor implements BeanPostProcessor{
        /**
         * bean:实例对象
         * beanName:在配置文件中配置的类的标识.(就是id或者是name,如果你没id,name也行)
         */
        //关键是第五步和第八步是怎么增强的.
        //第五步和第八步只要你有一个类创建它都会执行的.整个生命周期不不用都记下来,关键是第五步和第八步.这两个可以做一些增强的操作.
        //Spring有很多内容都是基于后处理bean:BeanPostProcessor的.BeanPostProcessor,都是基于它的.
        public Object postProcessBeforeInitialization(Object bean, String beanName)
                throws BeansException {
            
            System.out.println("第五步:初始化之前执行....");//初始化之前执行
            return bean;//什么都没干,直接返回bean.直接返回bean代表根本没增强,什么事都没干.
        }
    
        public Object postProcessAfterInitialization(final Object bean, String beanName)
                throws BeansException {
            System.out.println("第八步:初始化后执行....");
            //有bean对象,有它的实例   实例化一个,相当于又创建一个helloService,现在要增强它
            //动态代理:Proxy.newProxyInstance()对实现接口的类生成代理 增强一个类的某个方法的时候有三种方式:继承、装饰者、动态代理。其中动态代理是最为灵活的一种方式
            //jdk的动态代理是必须对实现接口的类生成代理  但是Spring里面有别的办法
            //newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
            //类的加载器,interfaces类实现的接口,InvocationHandler类的处理器
            //if(bean.getClass().getName().equals("CustomerServiceImpl")){//调CustomerService里面的任何一个方法都相当于执行invoke
            //if(bean.getClass().getName().equals("customerService")){//调CustomerService里面的任何一个方法都相当于执行invoke
            //if(bean.getClass().getName().equals("CustomerService")){//调CustomerService里面的任何一个方法都相当于执行invoke
            //if(beanName.equals("CustomerService")){//配置文件里面叫customerService
            if(beanName.equals("customerService")){
            Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler(){
                //在外面调用任何一个方法都相当于执行我们这里面的这个invoke()方法
                //要是只想对CustomerService增强,不想对别的Service增强,那就在这里加个判断,否则它是对所有的类都执行这个后处理bean的.
                //调用目标方法的时候,调用invoke方法.
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    //对它里面进行增强
                    //return method.invoke(bean,args);//相当于是没有进行增强
                    //如果不是对所有方法都进行增强,判断
                    if("add".equals(method.getName())){//是add()才增强
                        //进行时间监控或者是权限校验都可以
                        System.out.println(System.currentTimeMillis());//时间监控
                        //System.out.println("权限校验.....");
                        Object result = method.invoke(bean, args);
                        System.out.println(System.currentTimeMillis());//时间监控
                        return result;
                    }
                    return method.invoke(bean, args);//不是add()方法就不进行增强
                }
                
            });//返回实现这个接口的一个代理
            //第二个参数得到这个类实现的所有的接口 
            //第三个参数是一个处理器  处理器它是一个接口  两种办法  第一种办法你自己写个类实现这个接口,第二种办法直接匿名内部类
            return proxy;//如果这个类是CutomerService,直接返回一个代理对象
            }
            
            return bean;//其他的类不增强,return bean;
            //放开if,不管你哪个类都会给你生成代理,给你增强
        }
    }
    package cn.itcast.spring3.demo4;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanNameAware;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    
    public class CustomerServiceImpl implements CustomerService,BeanNameAware,ApplicationContextAware,InitializingBean,DisposableBean{
        //演示CustomerService完整的生命周期
        
        //第一步是实例化这个bean,那样就会调用它的构造方法
        //第一步:只要一加载配置文件就帮我们创建这个类了。
        @SuppressWarnings("unused")
        private String name;
        
    
    
        public void setName(String name) {
            System.out.println("第二步:属性的注入.");
            this.name = name;
        }
    
    
        public CustomerServiceImpl() {
            super();
            System.out.println("第一步:实例化类.");
        }
        
        
        public void add(){//第九步:执行业务逻辑
           System.out.println("添加客户....");
        }
    
        public void find(){//第九步:执行业务逻辑
           System.out.println("查询客户.....");
        }
    
    
        public void setBeanName(String name) {
            System.out.println("第三步:注入配置的类的名称"+name);//什么是类的名称?就是那个id
            //  <bean id="customerService" class="cn.itcast.spring3.demo4.CustomerService">
            //就是我们在Spring中对这个类起了一个id。它就会把这个名字给你注入到这个程序里面,让我们这个类CustomerService了解Spring的容器。它就把你配置的那个id给你传过来了。
            
            
            
        }
    
        //第四步也是让我们这个类来了解Spring容器,只不过它是把工厂注入进来了。它是把ApplicationContext注入进来了。
        //它就让我们本身这个类了解Spring这个容器
        //第三步和第四步都是为了让我们这个类来了解Spring容器。
        public void setApplicationContext(ApplicationContext applicationContext)
                throws BeansException {
        System.out.println("第四步:注入applicationContext"+applicationContext);
        }
    
    
        public void afterPropertiesSet() throws Exception {
            System.out.println("第六步:属性设置后执行.....");
            
        }
        
        public void setup(){
            System.out.println("第七步:调用手动设置的初始化方法....");
            
        }
    
    
        public void destroy() throws Exception {
            System.out.println("第十步:调用销毁的方法....");
            
        }
        public void teardown(){
            
            System.out.println("第十一步:调用手动销毁的方法....");
        }
    }
    package cn.itcast.spring3.demo4;
    
    public interface CustomerService {
       public void add();
       public void find();
       
    }
    package cn.itcast.spring3.demo4;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    @SuppressWarnings("unused")
    public class SpringTest4 {
    
        @Test
        //Bean完整的生命周期
        
        public void demo1(){
            //ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            
            
            //CustomerServiceImpl customerService = (CustomerServiceImpl) applicationContext.getBean("customerService");
            CustomerService customerService = (CustomerService) applicationContext.getBean("customerService");
            customerService.add();
            customerService.find();
            applicationContext.close();
        
        }
        
        
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 别去schema,schema是文件,本地的文件,你得引那个头 -->
    
    <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">
    <!-- demo1快速入门================================================= -->
    <!-- 把接口和实现类在这个配置文件中配置,有了实现类的全路径之后到时候才能用工厂反射 -->
       
       <!-- 通过一个<bean>标签来设置类的信息,通过id属性为类起个标识. -->
        <!-- 接口,实现类,配置文件也都有了 -->
        <!-- 现在有一个工厂Spring为我们提供好了,其实就是解析这个XML文件 -->
        <!-- 这个工厂你自己写会不会写?你用dom4j找里面的bean标签,找到class的属性值,然后就可以Class.forName()反射生成类的实例.其实Spring
             也是这么做的,只不过工厂由Spring提供好了
         -->
        <bean id="helloService" class="cn.itcast.spring3.demo1.HelloServiceImpl">
             <!-- 使用<property>标签注入属性 
             value指的是普通值
             ref指的是对象
             -->
        <property name="info"  value="传智播客"></property>
        </bean>
        <!-- demo1快速入门 -->
        <!-- demo2Bean的实例化 -->
        <!-- 默认情况下使用的就是无参数的构造方法. -->
        <!-- 
        <bean id="bean1" class="cn.itcast.spring3.demo2.Bean1"></bean>
        -->
        <!-- 
        <bean name="bean1" class="cn.itcast.spring3.demo2.Bean1"></bean>
        -->
        <!-- 第二种使用静态工厂实例化 不能写class了,因为现在不是由Spring直接帮你创建对象了-->
        <!--  
        <bean id="bean2" class="cn.itcast.spring3.demo2.Bean2Factory" factory-method="getBean2"></bean>
        -->
        <!-- 第三种使用实例工厂实例化 -->
        <!-- 
        <bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>
        -->
        <!-- 要先把Bean3Factory实例化 -->
        <!--  
        <bean id="bean3Factory" class="cn.itcast.spring3.demo2.Bean3Factory"></bean>
        -->
        <!-- demo2Bean的实例化======================  end-->
        
        <!-- demo3Bean的作用范围======================= -->
        <!--  
        <bean id="customer" class="cn.itcast.spring3.demo3.Customer" scope="prototype"></bean>
        -->
        <!-- 
        <bean id="product" class="cn.itcast.spring3.demo3.Product" init-method="setup" destroy-method="teardown" scope="singleton">
           <property name="name" value="空调">-->
           <!-- 把Product类的属性name注入进来 -->
           <!-- 
           </property>
        </bean>    
     -->
    
           <!-- demo4Bean的生命周期======================= -->
           <bean id="customerService" class="cn.itcast.spring3.demo4.CustomerServiceImpl" init-method="setup"  destroy-method="teardown">
           
              <property name="name" value="itcast"></property>
           </bean>
           <!-- 后处理Bean是由Spring容器自动调用不用你管,我们起个id是为了我们在程序中去获得它。但是这个类不用由我们获得, 由Spring自动调用。cn.itcast.spring3.demo4.MyBeanPostProcessor是后处理Bean-->
            <bean class="cn.itcast.spring3.demo4.MyBeanPostProcessor"></bean>
           
    </beans>
  • 相关阅读:
    学习ActiveMQ(七):JMS消息的事务管理
    2020杭电多校第三场题解
    2020牛客暑期多校训练营第六场题解
    2020杭电多校第二场题解
    2020 Petrozavodsk Winter Camp, Jagiellonian U Contest 部分题解
    Educational Codeforces Round 86 (Rated for Div. 2) 部分题解
    2020, XIII Samara Regional Intercollegiate Programming Contest 题解
    2019 JUST Programming Contest题解
    2019-2020 ICPC Asia Taipei-Hsinchu Regional Contest 部分题解
    2019 ICPC Universidad Nacional de Colombia Programming Contest 题解
  • 原文地址:https://www.cnblogs.com/ZHONGZHENHUA/p/6722382.html
Copyright © 2020-2023  润新知