zoukankan      html  css  js  c++  java
  • Spring_4_工厂高级特性

    1. 对象的生命周期

    • 什么是对象的⽣命周期?
      ⼀个对象 创建、存活、消亡 的⼀个完整过程。
    • 为什么要学习对象的⽣命周期? 由 Spring 负责对象的 创建、存活、销毁,了解⽣命周期,有利于我们使用好 Spring 为我们创建的对象。
    • ⽣命周期的 3 个阶段: 创建阶段 —> 初始化阶段 —> 销毁阶段

    1.1 创建阶段

    Spring 工厂何时创建对象?'

    • scope="prototype":Spring 工厂在获取对象 ctx.getBean("xxx") 的同时,创建对象。
    • scope="singleton":Spring 工厂创建的同时,创建对象。 通过配置 <bean lazy-init="true"/> 也可以实现工厂获取对象的同时,创建对象。 通过配置 <bean lazy-init="true"/> 也可以实现工厂获取对象的同时,创建对象。

    1.2 初始化阶段

    什么时候? Spring 工厂在创建完对象后,调用对象的初始化方法,完成对应的初始化操作。 初始化方法提供:程序员根据需求,提供初始化方法,最终完成初始化操作。 初始化方法调用:Spring 工厂进行调用。

    提供初始化方法的两种方式:

    1. InitializingBean 接口:

      public class Product implements InitializingBean {
          //程序员根据需求实现的方法, 完成初始化操作
          @Override
          public void afterPropertiesSet() throws Exception {
              System.out.println("Product.afterPropertiesSet");
          }
      }
      
    2. 对象中提供一个普通的初始化方法,配置文件种配置 init-method:

      public class Product {
          public void myInit() {
              System.out.println("Product.myInit");
          }
      }
      
      <bean id="product" class="com.yusael.life.Product" init-method="myInit"/>
      
    • 初始化操作的细节分析:
      1. 如果⼀个对象既实现 InitializingBean 同时⼜提供的 普通的初始化方法,执行顺序? 先执行 InitializingBean,再执行 普通初始化方法。
      2. 注入⼀定发⽣在初始化操作的前面。
      3. 初始化操作到底是什么? 资源的初始化:数据库、IO、网络、…

    1.3 销毁阶段

    Spring 销毁对象前,会调用对象的销毁方法,完成销毁操作。

    • Spring 什么时候销毁所创建的对象?ctx.close(); 销毁方法提供:程序员根据业务需求,定义销毁方法,完成销毁操作

    销毁方法调用:Spring 工厂进行调用。

    开发流程与初始化操作一样,提供销毁方法的两种方式:

    1. DisposableBean 接口:

      public class Product implements DisposableBean {
          // 程序员根据⾃⼰的需求, 定义销毁方法, 完成销毁操作
          @Override
          public void destroy() throws Exception {
              System.out.println("Product.destroy");
          }
      }
      
    2. 对象中提供一个普通的销毁方法,配置文件种配置 destroy-method:

      public class Product {
          // 程序员根据⾃⼰的需求, 定义销毁方法, 完成销毁操作
          public void myDestory() {
              System.out.println("Product.myDestory");
          }
      }
      
      <bean id="product" class="com.yusael.life.Product" destroy-method="myDestory"/>
      
    3. 销毁阶段细节分析: 销毁方法的操作只适用于 scope="singleton",初始化操作都适用。
    4. 销毁操作到底是什么? 资源的释放:io.close()、connection.close()、…

    1.4 总结

    public class Product implements InitializingBean, DisposableBean {
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            System.out.println("Product.setName");
            this.name = name;
        }
    
        Product() { // 创建
            System.out.println("Product.Product");
        }
    
        // 程序员根据需求实现的方法, 完成初始化操作
        public void myInit() {
            System.out.println("Product.myInit");
        }
    
        // 程序员根据需求实现的方法, 完成初始化操作
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("Product.afterPropertiesSet");
        }
    
        public void myDestory() {
            System.out.println("Product.myDestory");
        }
    
        // 程序员根据⾃⼰的需求, 定义销毁方法, 完成销毁操作
        @Override
        public void destroy() throws Exception {
            System.out.println("Product.destroy");
        }
    }
    
    <bean id="product" class="com.yusael.life.Product" init-method="myInit" destroy-method="myDestory">
      <property name="name" value="yusael"/>
    </bean>
    

    img1

    2. 配置文件参数化

    配置文件参数化:把 Spring 配置文件中需要经常修改的字符串信息,转移到⼀个更小的配置文件中。

    1. Spring 的配置文件中是否存在需要经常修改的字符串? 存在:以数据库连接相关的参数…
    2. 经常变化字符串,在 Spring 的配置文件中,直接修改不利于项目维护(修改)
    3. 转移到⼀个小的配置文件(.properties)利于维护(修改)

    优点:利于 Spring 配置文件的维护(修改)

    2.1 配置文件参数的开发步骤

    1. 提供⼀个小的配置文件(.properities) 名字:没有要求 放置位置:没有要求

      jdbc.driverClassName = com.mysql.jdbc.Driver
      jdbc.url = jdbc:mysql://localhost:3306/spring?useSSL=false
      jdbc.username = root
      jdbc.password = 1234
      
    2. Spring 的配置文件与小配置文件进行整合:

      <!--Spring的配置文件与⼩配置文件进行整合-->
      <!--resources 下的文件在整个程序编译完后会被放到 classpath 目录下,src.main.java中的文件也是-->
      <context:property-placeholder location="classpath:/db.properties"/>
      
    3. 在 Spring 配置文件中通过 ${key} 获取小配置文件中对应的值:

      <bean id="conn" class="com.yusael.factorybean.ConnectionFactoryBean">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
      </bean>
      

    3. 自定义类型转换器

    产生原因:当 Spring 内部没有提供特定类型转换器时,而程序员在应用的过程中还需要使用,那么 就需要程序员⾃⼰定义类型转换器。

    3.1 自定义类型转换器开发步骤

    1. 类 implements Converter 接口

      public class MyDateConverter implements Converter<String, Date> {
          /*
            convert方法作用: String ---> Date
            SimpleDateFormat sdf = new SimpleDateFormat();
            sdf.parset(String) ---> Date
      
            参数:
            source : 代表的是配置文件中, 日期字符串 <value>2020-10-11</value>
            return : 当把转换好的 Date 作为 convert 方法的返回值后,
            Spring ⾃动的为birthday属性进行注入(赋值)
          */
          @Override
          public Date convert(String source) {
              Date date = null;
              try {
                  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                  date = sdf.parse(source);
              } catch (ParseException e) {
                  e.printStackTrace();
              }
              return date;
          }
      }
      
    2. 在 Spring 的配置文件中进行配置; 先创建 MyDateConverter 对象,再注册类型转换器;

      <!--创建 MyDateConverter 对象-->
      <bean id="myDateConverter" class="com.yusael.converter.MyDateConverter"/>
      <!--用于注册类型转换器-->
      <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
          <set>
            <ref bean="myDateConverter"/>
          </set>
        </property>
      </bean>
      
      <bean id="good" class="com.yusael.converter.Good">
        <property name="name" value="zhenyu"/>
        <property name="birthday" value="2012-12-12"/>
      </bean>
      
    3. 自定义类型转换器细节
      1. MyDateConverter 中的日期的格式,通过 依赖注入 的方式,由配置文件完成赋值。

        public class MyDateConverter implements Converter<String, Date> {
            private String pattern;
        
            @Override
            public Date convert(String source) {
                Date date = null;
                try {
                    SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                    date = sdf.parse(source);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                return date;
            }
        
            public String getPattern() {
                return pattern;
            }
        
            public void setPattern(String pattern) {
                this.pattern = pattern;
            }
        }
        
        <!-- 配置文件完成对日期格式的赋值 -->
        <bean id="myDateConverter" class="com.yusael.converter.MyDateConverter">
          <property name="pattern" value="yyyy-MM-dd"/>
        </bean>
        
      2. ConversionSeviceFactoryBean 定义 id属性,值必须是 conversionService;

        <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
          <property name="converters">
            <set>
              <ref bean="myDateConverter"/>
            </set>
          </property>
        </bean>
        
      3. Spring 框架其实内置了日期类型的转换器:日期格式必须是 2020/05/01。

        <bean id="good" class="com.yusael.converter.Good">
          <property name="name" value="zhenyu"/>
          <property name="birthday" value="2012/12/12"/>
        </bean>
        

    4. 后置处理 Bean

    BeanPostProcessor 作用:对 Spring 工厂所创建的对象,进行再加工。(AOP 的底层实现)

    4.1 后置处理 Bean 原理分析

    img2

    4.2 实现 BeanPostProcessor 接口中规定的两个方法

    • postProcessBeforeInitialization 作用:Spring 创建完对象,并进行注入后,可以运行 Before ⽅法进行加工; 通过方法的参数获得 Spring 创建好的对象,最终通过返回值交给 Spring 框架。

      public Object postProcessBeforeInitialization(Object bean, String beanName) {
          return bean;
      }
      
    • postProcessAfterInitialization 作⽤:Spring 执行完对象的初始化操作后,可以运行 After ⽅法进行加工; 通过方法的参数获得 Spring 创建好的对象,最终通过返回值交给 Spring 框架。

      public Object postProcessAfterInitialization(Object bean, String beanName) {
          return bean;
      }
      
    • 应用 实战中:很少处理 Spring 的初始化操作,没有必要区分 Before,After。只需要实现其中一个,建议是 After 方法即可

    4.3 BeanPostProcessor 开发步骤

    1. 类 实现 BeanPostProcessor 接口

      public class MyBeanPostProcessor implements BeanPostProcessor {
          @Override
          public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              return null;
          }
      
          @Override
          public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              Category category = (Category) bean;
              category.setName("yusael");
              return category;
          }
      }
      
    2. Spring 配置文件中进行配置

      <bean id="myBeanPostProcessor" class="com.yusael.beanpost.MyBeanPostProcessor"/>
      
    3. 细节 BeanPostProcessor 会对 Spring 工厂创建的所有对象进行加工。如果工厂创建了多个不同的对象,要注意区别传入的对象:

      @Override
      public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
          if (bean instanceof  Category) {
              Category category = (Category) bean;
              category.setName("yusael");
              return category;
          }
          return bean;
      }
      
  • 相关阅读:
    Java NIO中的缓冲区Buffer(二)创建/复制缓冲区
    Java NIO中的缓冲区Buffer(一)缓冲区基础
    Java中的反射
    Java SE 9(JDK9)环境安装及交互式编程环境Jshell使用示例
    Spring Data JPA例子[基于Spring Boot、Mysql]
    Spring Session
    Spring Data Redis示例
    Spring IO Platform简介及示例
    使用Spring Boot开发 “Hello World” Web应用
    2017/01/13,今天正好是开通博客园一周年,谈谈自己的一些想法
  • 原文地址:https://www.cnblogs.com/instinct-em/p/13381175.html
Copyright © 2011-2022 走看看