精华内容
下载资源
问答
  • Spring对象的生命周期、配置文件参数化、自定义类型转换器、后置处理Bean1.对象的生命周期什么是对象的生命周期?生命周期的三个阶段:创建阶段初始化阶段销毁阶段测试2.配置文件参数化3.自定义类型转换器开发步骤:...

    1.对象的生命周期

    1.1 什么是对象的生命周期?

    •  对象 创建-存活-消亡 整个过程。
      
    •  以前由GC回收,现在由Spring管理,有助于使用好Spring为我们创建的对象。
      

    1.2 生命周期的三个阶段:

    •   创建阶段 —> 初始化阶段 —> 销毁阶段
      

    1.2.1 创建阶段

    • Spring工厂何时创建对象?
      scope="singleton" :工厂创建的同时,对象创建。可以添加lazy-init属性为true,实现prototype的效果
      scope="prototype" :获取对象的时候创建 getBean()

    1.2.2 初始化阶段

    Spring创建完对象之后,调用对象的初始化方法,完成对应的初始化操作

    • 提供:程序猿根据需求,提供初始化方法,最终完成初始化操作

    • 调用:Spring工厂进行调用
      方式一:实现initializingBean接口
      方式二:写一个普通方法,在bean标签中添加属性 init-method=“xxx()”

    • 细节分析:

    1. 如果既实现了接口,又提供了普通的初始化方法?
      先执行initializing的方法,再执行普通的初始化方法
    2. 初始化和注入谁先进行?
      先进行注入,再执行初始化方法
    3. 什么叫初始化操作?
      资源的初始化:数据库,IO,网络。。。

    1.2.3 销毁阶段

    调用销毁方法,完成销毁操作

    • 销毁方法:程序猿根据需求定义销毁方法,完成销毁操作
    • 何时调用:Spring工厂完成调用
    • Spring什么时候销毁对象?
      工厂关闭后,context.close()

    方式一:DisposableBean
    方式二:定义普通销毁方法,bean标签中设置属性destroy-method

    • 细节:
      1.销毁方法的操作只适用于scope=“singleton”
      2.什么叫销毁操作?
      主要指的是 资源的释放操作:IO、Connection

    1.3 测试

    测试bean

    package zyc.stu.Spring5_45_53.Life;
    
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    
    /**
     * @author zhuZiGe_
     * @create 2020-09-10-18:01
     */
    public class Product implements InitializingBean, DisposableBean {
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            System.out.println("setName");
            this.name = name;
        }
    
        public Product() {
            System.out.println("Product.Constructor");
        }
    
        //初始化方法:执行一些初始化操作,会被spring调用
        public void afterPropertiesSet() throws Exception {
            System.out.println("afterPropertiesSet()");
        }
    
        //普通方法,bean标签内调用也可以成为初始化方法
        public void myInit(){
            System.out.println("Product.myInit");
        }
    
        //销毁方法:销毁操作(资源释放)
        public void destroy() throws Exception {
            System.out.println("destroy()");
        }
    
        //普通方法:bean标签内调用也可以成为销毁方法
        public void myDestroy(){
            System.out.println("Product.myDestroy");
        }
    }
    
    <bean id="product" class="zyc.stu.Spring5_45_53.Life.Product" scope="prototype" init-method="myInit" destroy-method="myDestroy">
            <property name="name">
                <value>zyc</value>
            </property>
        </bean>
    

    测试

        @Test
        public void test2(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
            //Product product = (Product) context.getBean("product");
            context.close();
        }
    

    1.4 总结:从上到下依次进行

    在这里插入图片描述

    2.配置文件参数化

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

    2.1 为什么要参数化

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

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

    2.2.1 准备配置文件

    提供⼀个小的配置文件(.properities)

    jdbc.driverClassName = com.mysql.jdbc.Driver
    jdbc.url = jdbc:mysql://localhost:3306/springdemo?useSSL=false
    jdbc.username = root
    jdbc.password = root
    

    2.2.2 整合

    Spring 的配置文件与小配置文件进行整合:

    <!--resources 下的文件在整个程序编译完后会被放到 classpath 目录下,src.main.java中的文件也是-->
    <context:property-placeholder location="classpath:/db.properties"/>
    

    2.2.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.自定义类型转换器

    类型转换器:将xml中的字符串类型转换为其他类型
    自定义:当Spring内部没有提供特定的类型转换器时,可以根据需求自定义类型转换器

    3.1 开发步骤:

    1. 新建转换器类,实现Converter<s,t>接口 s:原始类型 v:转换后的类型(以后Spring在注入v类型的时候就知道如何处理了)
    2. Spring配置文件配置
    3. Spring配置文件注册:告知Spring它是一个类型转换器

    3.2 细节:

    ConversionServiceFactoryBean内部有个set<?> Converters集合属性,所以配置文件中,property赋值时采用set子标签,内部再引用第二步配置好的自定义的bean.

    创建测试bean Person:

    package zyc.stu.Spring5_54_61.Converter;
    
    import java.io.Serializable;
    import java.util.Date;
    
    /**
     * @author zhuZiGe_
     * @create 2020-09-11-10:43
     */
    public class Person implements Serializable {
        private String name;
        private Date birthday;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public Person(String name, Date birthday) {
            this.name = name;
            this.birthday = birthday;
        }
    
        public Person() {
        }
    }
    
    

    创建Convertor:实现接口

    package zyc.stu.Spring5_54_61.Converter;
    
    import org.springframework.core.convert.converter.Converter;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     * @author zhuZiGe_
     * @create 2020-09-11-10:53
     */
    public class MyDateConverter implements Converter<String,Date> {
    
        private String format;
    
        public String getFormat() {
            return format;
        }
    
        public void setFormat(String format) {
            this.format = format;
        }
    
        /**
         * convert方法作用:String-->Date
         *                  SimpleDateFormat sdf = new SimpleDateFormat();
         *                  sdf.parse(string)
         * @param s 代表的是配置文件中的value对应的值
         * @return date 自动注入到到对应property
         */
        public Date convert(String s) {
            Date date = null;
            try {
                SimpleDateFormat sdf= new SimpleDateFormat(this.format);
                date = sdf.parse(s);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return date;
        }
    }
    

    配置
    步骤:

    1. 将自定义的类型转换器纳入Spring管理

    2. 注册类型转换器
      ConversionServiceFactoryBean的id值只能为conversionService

       自定义的类型转换器都要纳入ConversionServiceFactoryBean中
      
        <!--  自定义类型转换器  -->
        <bean id="myDateConverter" class="zyc.stu.Spring5_54_61.Converter.MyDateConverter">
            <property name="format" value="yyyy-MM-dd"/>
        </bean>
            <!-- 注册 -->
        <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
            <property name="converters">
                <set>
                    <ref bean="myDateConverter"/>
                </set>
            </property>
        </bean>
    
        <bean id="person" class="zyc.stu.Spring5_54_61.Converter.Person">
            <property name="name" value="zyc"/>
            <property name="birthday" value="2020-9-11"/>
        </bean>
    

    测试

        @Test
        public void test2(){
            ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext1.xml");
            Person person = (Person) context.getBean("person");
            System.out.println(person.getBirthday());
        }
    

    3.3 思考

    1. 日期格式作为参数交给spring管理,依赖注入解耦
    2. 注册时,bean的id属性必须为conversionService,不然spring找不到
    3. Spring框架内置了日期类型转换器 格式为2020/9/11

    4.后置处理bean

    BeanPostProcessor作用:对Spring工厂创建的对象进行再加工。

    4.1 Spring创建对象步骤

    实现BeanPostProcessor接口前:

    •      构造方法创建bean-->InitializingBean-->init-method=""
      

    实现BeanPostProcessor接口后:

    •      构造方法创建bean-->postProcessBeforeInitialization()-->InitializingBean-->init-method=""-->postProcessAfterInitialization()
      

    4.2 两个重写的方法

    postProcessBeforeInitialization(Object,String):加工bean,对象作为第一个参数,id作为第二个参数
    postProcessAfterInitialization(Object,String):再次加工bean,对象作为第一个参数,id作为第二个参数

    4.3 实战建议

    基本上不写初始化操作,对于可能出现的加工操作就没必要区分before和after了,只要实现其中一个after即可,before仅充当一个搬运工的角色

    •      before可以什么都不干,但必须返还bean给Spring
      

    4.4 细节

    BeanPostProcessor会对Spring工厂中(仅限于注册的xml文件中的bean)所有的对象进行加工,如果只处理某个对象,别忘了类型判断。

    测试bean

    package zyc.stu.Spring5_54_61.beanPostProcess;
    
    /**
     * @author zhuZiGe_
     * @create 2020-09-11-15:37
     */
    public class Category {
        private int id;
        private String name;
    
        @Override
        public String toString() {
            return "Category{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    '}';
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Category() {
        }
    
        public Category(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }
    

    后置处理bean

    • before一般只做传递bean
    • after中要做类型判断:
      在同一个Spring的配置文件中存在很多其他的bean,如果没有将这些bean的scope属性设置为prototype,则在创建工厂时就会报错,类型转换异常;就算设为了prototype,当你不小心获取这些bean的时候也会报同样的错误。因为这些bean都会经过Processor的处理
    package zyc.stu.Spring5_54_61.beanPostProcess;
    
    import org.springframework.beans.BeansException;
    
    /**
     * @author zhuZiGe_
     * @create 2020-09-11-15:40
     */
    public class BeanPostProcessor implements org.springframework.beans.factory.config.BeanPostProcessor {
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if(bean instanceof Category){
                Category cat = (Category) bean;
                cat.setName("hahah");
            }
            return bean;
        }
    }
    

    配置

        <bean id="category" class="zyc.stu.Spring5_54_61.beanPostProcess.Category">
            <property name="id" value="12"/>
            <property name="name" value="嘻嘻嘻"/>
        </bean>
        <bean id="myBeanPostProcessor" class="zyc.stu.Spring5_54_61.beanPostProcess.BeanPostProcessor"/>   
    

    测试

        @Test
        public void test3(){
            ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext1.xml");
            Category category = (Category) context.getBean("category");
            System.out.println(category);
        }
    
    展开全文
  • 细节3、后置处理Bean 1、对象的⽣命周期 1、什么是对象的⽣命周期 指的⼀个对象创建、存活、消亡的⼀个完整过程 2、 为什么要学习对象的⽣命周期 由Spring负责对象的创建、存活、销毁,了解⽣命周期,有利于我们...

    1、对象的⽣命周期

    在这里插入图片描述

    1、什么是对象的⽣命周期

    指的是⼀个对象创建、存活、消亡的⼀个完整过程

    2、 为什么要学习对象的⽣命周期

    由Spring负责对象的创建、存活、销毁,了解⽣命周期,有利于我们使⽤好Spring为我们创建的对象

    ⽣命周期的3个阶段

    1、创建阶段

    Spring⼯⼚何时创建对象
    scope=“singleton”
    Spring⼯⼚创建的同时,对象的创建
    注意:设置scope=singleton 这种情况下 也需要在获取对象的同时,创建对象

    scope=“prototype”
    Spring⼯⼚会在获取对象的同时,创建对象ctx.getBean("")

    2、、初始化阶段

    Spring⼯⼚在创建完对象后,调⽤对象的初始化⽅法,完成对应的初始化操作

    1. 初始化⽅法提供:程序员根据需求,提供初始化⽅法,最终完成初始化操作
    2. 初始化⽅法调⽤:Spring⼯⼚进⾏调⽤

    InitializingBean接⼝
    //程序员根据需求,实现的⽅法,完成初始化操作
    public void
    afterProperitesSet(){
    }

    对象中提供⼀个普通的⽅法
    public void myInit(){
    }

    细节分析
    1、如果⼀个对象即实现InitializingBean 同时⼜提供的 普通的初始化⽅法 顺序

    1. InitializingBean
    2. 普通初始化⽅法

    2、注⼊⼀定发⽣在初始化操作的前⾯
    3、什么叫做初始化操作
    资源的初始化:数据库 IO ⽹络

    3、销毁阶段

    Spring销毁对象前,会调⽤对象的销毁⽅法,完成销毁操作

    1. Spring什么时候销毁所创建的对象? ctx.close();
    2. 销毁⽅法:程序员根据⾃⼰的需求,定义销毁⽅法,完成销毁操作
      调⽤:Spring⼯⼚完成调⽤

    DisposableBean
    public void destroy()throws
    Exception{

    }

    定义⼀个普通的销毁⽅法
    public void myDestroy()throws
    Exception{
    }

    细节分析
    1.销毁⽅法的操作只适⽤于 scope=“singleton”
    2. 什么叫做销毁操作
    主要指的就是 资源的释放操作 io.close() 、connection.close();

    2、配置⽂件参数化

    把Spring配置⽂件中需要经常修改的字符串信息,转移到⼀个更⼩的配置⽂件中

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

    配置⽂件参数化:利于Spring配置⽂件的维护(修改)

    1、配置⽂件参数的开发步骤

    提供⼀个⼩的配置⽂件(.properities)

    名字:随便
    放置位置:随便
    jdbc.driverClassName =com.mysql.jdbc.Driver
    jdbc.url =jdbc:mysql://localhost:3306/suns? useSSL=false
    jdbc.username = root
    jdbc.password = 123456
    

    Spring的配置⽂件与⼩配置⽂件进⾏整合

    applicationContext.xml
    <context:property-placeholder location="classpath:/db.properties"/>
    

    在Spring配置⽂件中通过${key}获取⼩配置⽂件中
    对应的值
    在这里插入图片描述

    3、⾃定义类型转换器

    1、类型转换器

    作⽤:Spring通过类型转换器把配置⽂件中字符串类型的数据,转换成了对象中成员变量对应类型的数据,进⽽完成了注⼊
    在这里插入图片描述

    2、⾃定义类型转换器

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

    类 implements Converter接⼝

    public class MyDateConverter
    implements Converter<String,
    Date> {
    
     @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;
     }
    

    convert⽅法作⽤:String —> Date
    SimpleDateFormat sdf = newSimpleDateFormat();
    sdf.parset(String) —> Date
    param:source 代表的是配置⽂件中 ⽇期字符串 2020-10-11
    return : 当把转换好的Date作为convert⽅法的返回值后,Spring⾃动的为birthday属性进⾏注⼊(赋值)

    在Spring的配置⽂件中进⾏配置

    MyDateConverter对象创建出来

    <bean id="myDateConverter"  class="xxxx.MyDateConverter"/>
    

    类型转换器的注册

    ⽬的:告知Spring框架,我们所创建的MyDateConverter是⼀个类型转换器
    <!--⽤于注册类型转换器-->
    <bean id="conversionService"  class="org.springframework.context.support.ConversionServiceFa
    ctoryBean">
     <property name="converters">
     <set>
     <ref bean="myDateConverter"/>
     </set>
     </property>
    </bean>
    

    3、 细节

    MyDateConverter中的⽇期的格式,通过依赖注⼊的⽅式,由配置⽂件完成赋值。

    public class MyDateConverter
    implements Converter<String,Date> {
     private String pattern;
     public String getPattern() {
     return pattern;
     }
     public void  setPattern(String pattern) {
     this.pattern = pattern;
     }
    
    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;
     }
    }
    
    
    <!--Spring创建MyDateConverter类型对象-->
    <bean id="myDateConverter" class="com.baizhiedu.converter.MyDateConverter">
     <property name="pattern"  value="yyyy-MM-dd"/>
    </bean>
    

    ConversionSeviceFactoryBean 定义 id属性 值必须conversionService

    Spring框架内置⽇期类型的转换器
    ⽇期格式:2020/05/01 (不⽀持 :2020-05-01)

    3、后置处理Bean

    BeanPostProcessor作⽤:对Spring⼯⼚所创建的对象,进⾏再加⼯。

    AOP底层实现:
    注意:BeanPostProcessor接⼝xxxx(){
    }
    后置处理Bean的运⾏原理分析
    在这里插入图片描述`程序员实现BeanPostProcessor规定接⼝中的⽅法:
    Object postProcessBeforeInitiallization(Object bean String beanName)
    作⽤:Spring创建完对象,并进⾏注⼊后,可以运⾏Before⽅法进⾏加⼯获得Spring创建好的对象 :通过⽅法的参数最终通过返回值交给Spring框架

    实战中:
    很少处理Spring的初始化操作:没有必要区分Before After。只需要实现其中的⼀个After⽅法即可
    注意:
    postProcessBeforeInitiallization
    return bean对象

    BeanPostProcessor的开发步骤
    1、 实现 BeanPostProcessor接⼝

    public class MyBeanPostProcessor implements BeanPostProcessor
    {
     @Override
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws  BeansException {
     return bean;
     }
    //修改了categroy 的name 值
    public Object  postProcessAfterInitialization(Object bean, String  beanName) throws BeansException {
     Categroy categroy =(Categroy) bean;
    
    categroy.setName("xiaowb");
     return categroy;
     }
    }
    

    Spring的配置⽂件中进⾏配置

    <bean  id="myBeanPostProcessor"  class="xxx.MyBeanPostProcessor"/>
    

    BeanPostProcessor细节

    BeanPostProcessor会对Spring⼯⼚中所有创建的对象进⾏加⼯。

    展开全文
  • 什么是对象的⽣命周期? ⼀个对象 创建、存活、消亡 的⼀个完整过程。 为什么要学习对象的⽣命周期? 由 Spring 负责对象的 创建、存活、销毁,了解⽣命周期,有利于我们使用好 Spring 为我们创建的对象。 ⽣命...

    对象的生命周期

    什么是对象的⽣命周期?

    • ⼀个对象 创建、存活、消亡 的⼀个完整过程。

    为什么要学习对象的⽣命周期?

    • Spring 负责对象的 创建、存活、销毁,了解⽣命周期,有利于我们使用好 Spring 为我们创建的对象。

    ⽣命周期的 3 个阶段:

    • 创建阶段 —> 初始化阶段 —> 销毁阶段

    创建阶段

    Spring 工厂何时创建对象?

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

    初始化阶段

    什么时候?

    • Spring 工厂在创建完对象后,调用对象的初始化方法,完成对应的初始化操作。

    初始化方法提供:由程序员根据需求,提供初始化方法,最终完成初始化操作。

    初始化方法调用:Spring 工厂进行调用

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

    • InitializingBean接口:
    public class Product implements InitializingBean {
    	// 程序员根据需求实现的方法
    	// 由 Spring工厂 调用,完成初始化操作
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("Product.afterPropertiesSet");
        }
    }
    
    <bean id="product" class="com.hey.life.Product" />
    
    • 对象中提供一个普通的初始化方法,配置文件种配置 init-method
    public class Product {
        public void myInit() {
            System.out.println("Product.myInit");
        }
    }
    
    <bean id="product" class="com.yusael.life.Product" init-method="myInit"/>
    

    与 FactoryBean接口 类似,如果不使用接口就可以在配置文件中配置方法。


    【注意】

    如果⼀个对象既实现 InitializingBean 同时⼜提供的 普通的初始化方法,执行顺序?

    • 执行 InitializingBean执行 普通初始化方法。

    注入⼀定发⽣在初始化操作的前面。正如接口的方法名那样 afterPropertiesSet,在属性设置之后

    初始化操作到底是什么?

    • 资源的初始化:数据库、IO、网络、…

    销毁阶段

    销毁阶段,即:Spring 销毁对象前,会调用对象的销毁方法,完成销毁操作

    Spring 什么时候销毁所创建的对象?

    • 在工厂关闭的时候,关闭之前会销毁工厂创建的对象。

    销毁方法提供:程序员根据业务需求,定义销毁方法,完成销毁操作

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

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

    • DisposableBean 接口:
    public class Product implements DisposableBean {
        // 程序员根据⾃⼰的需求, 定义销毁方法, 完成销毁操作
        @Override
        public void destroy() throws Exception {
            System.out.println("Product.destroy");
        }
    }
    

    对象中提供一个普通的销毁方法,配置文件种配置 destroy-method

    public class Product {
    	// 程序员根据⾃⼰的需求, 定义销毁方法, 完成销毁操作
        public void myDestory() {
            System.out.println("Product.myDestory");
        }
    }
    
    <bean id="product" class="com.yusael.life.Product" destroy-method="myDestory"/>
    

    【注意】

    • 销毁方法的操作只适用于 scope="singleton",初始化操作则都适用。

    销毁操作到底是什么?

    • 资源的释放:io.close()connection.close()、…

    对象的生命周期总结

    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>
    

    在这里插入图片描述

    配置文件参数化

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

    Spring 的配置文件中是否存在需要经常修改的字符串?

    • 存在:例如与数据库连接相关的参数

    在这里插入图片描述

    • 经常变化得字符串,在 Spring 的配置文件中直接修改不利于项目维护(修改)
    • 将之转移到⼀个小的配置文件(.properties)利于维护(修改)
    • 优点:利于 Spring 配置文件的维护(修改)

    开发步骤

    • 提供⼀个小的配置文件(.properities)
      名字:没有要求
      放置位置:没有要求
    jdbc.driverClassName = com.mysql.jdbc.Driver
    jdbc.url = jdbc:mysql://localhost:3306/spring?useSSL=false
    jdbc.username = root
    jdbc.password = 1234
    
    • 整合到 Spring 的配置文件中:
    <!--Spring的配置文件与⼩配置文件进行整合-->
    <!--resources 下的文件在整个程序编译完后会被放到 输出目录得 classes 目录下,
    		也就是 classpath路径下,
    		src.main.java 中的文件也会整合到这个目录之下-->
    <context:property-placeholder location="classpath:db.properties"/>
    
    • 使用时,可以直接在 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>
    

    自定义类型转换器

    类型转换器:Spring 通过 类型转换器 把 配置文件 中 字符串 类型的数据,转换成了对象中成员变量对应类型的数据,进而完成了注入

    在这里插入图片描述

    自定义一个类型转换器

    • 对于一些常见的数据类型,Spring有自带的类型转换器,可以转换字符串
    • 但是对于一些特殊的数据类型,Spring 内部没有提供特定类型转换器
    • 而程序员在应用的过程中还需要使用,那么就需要程序员⾃⼰定义类型转换器。

    实现步骤:

    1. 实现 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;
        }
    }
    
    1. 配置文件中,先创建 MyDateConverter 对象,再注册类型转换器
    <!--创建 MyDateConverter 对象-->
    <bean id="myDateConverter" class="com.yusael.converter.MyDateConverter"/>
    <!--用于注册类型转换器-->
    <!--这里的 id 和 class 是固定的,通过注入将转换器对象注入,即通过这个工厂类来生产转换器-->
    <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>
    

    这样就可以将配置文件中的字符串信息转换成日期类型的数据

    细节分析

    在上面的例子中,转换日期所使用的模板字符串是直接写在代码中的,这样耦合性很大,我们也可以将模板字符串再配置文件中进行配置,通过注入的方式,由配置文件赋值

    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>
    

    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>
    

    后置处理Bean

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

    BeanPostProcessor 实际是个接口,其中有两个方法需要实现:

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

    执行顺序:
    如果有属性需要注入,那就要在调用构造方法之后,先执行注入过后再去处理
    在这里插入图片描述

    尽管有两个可实现的方法,但是在实际应用中:很少处理 Spring 的初始化操作,没有必要区分 Before,After。

    • 只需要实现其中一个,建议是 After 方法即可。

    开发步骤

    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;
        }
    }
    
    1. Spring 配置文件中进行配置
    <bean id="myBeanPostProcessor" class="com.yusael.beanpost.MyBeanPostProcessor"/>
    

    【注意】
    BeanPostProcessor 会对 Spring 工厂 创建的所有对象进行加工。

    • 如果工厂创建了多个不同的对象,要注意区别传入的对象
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    	// 先判断是不是需要加工处理的 Bean
        if (bean instanceof  Category) {
            Category category = (Category) bean;
            category.setName("yusael");
            return category;
        }
        return bean;
    }
    
    展开全文
  • 什么是对象的⽣命周期? ⼀个对象 创建、存活、消亡 的⼀个完整过程。 为什么要学习对象的⽣命周期? 由 Spring 负责对象的 创建、存活、销毁,了解⽣命周期,有利于我们使用好 Spring 为我们创建的对象。 ⽣命...

    更多内容请查看笔记目录:【Spring 5.x】学习笔记汇总

    对象的生命周期

    什么是对象的⽣命周期?

    • ⼀个对象 创建、存活、消亡 的⼀个完整过程。

    为什么要学习对象的⽣命周期?

    • 由 Spring 负责对象的 创建、存活、销毁,了解⽣命周期,有利于我们使用好 Spring 为我们创建的对象。

    ⽣命周期的 3 个阶段:

    • 创建阶段 —> 初始化阶段 —> 销毁阶段

    创建阶段

    Spring 工厂何时创建对象?

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

    初始化阶段

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

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

    • InitializingBean 接口:
    public class Product implements InitializingBean {
    	//程序员根据需求实现的方法, 完成初始化操作
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("Product.afterPropertiesSet");
        }
    }
    
    • 对象中提供一个普通的初始化方法,配置文件种配置 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、网络、…

    销毁阶段

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

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

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

    销毁阶段细节分析

    1. 销毁方法的操作只适用于 scope="singleton",初始化操作都适用。
    2. 销毁操作到底是什么?
      资源的释放:io.close()connection.close()、…

    对象的生命周期总结

    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>
    

    在这里插入图片描述

    配置文件参数化

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

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

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

    配置文件参数的开发步骤

    • 提供⼀个小的配置文件(.properities)
      名字:没有要求
      放置位置:没有要求
    jdbc.driverClassName = com.mysql.jdbc.Driver
    jdbc.url = jdbc:mysql://localhost:3306/spring?useSSL=false
    jdbc.username = root
    jdbc.password = 1234
    
    • Spring 的配置文件与小配置文件进行整合:
    <!--Spring的配置文件与⼩配置文件进行整合-->
    <!--resources 下的文件在整个程序编译完后会被放到 classpath 目录下,src.main.java中的文件也是-->
    <context:property-placeholder location="classpath:/db.properties"/>
    

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

    自定义类型转换器

    类型转换器

    作用:Spring 通过 类型转换器 把 配置文件 中 字符串 类型的数据,转换成了对象中成员变量对应类型的数据,进而完成了注入。
    在这里插入图片描述

    自定义类型转换器

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

    [开发步骤]

    • 类 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;
        }
    }
    
    • 在 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>
    

    自定义类型转换器细节

    • 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>
    
    • ConversionSeviceFactoryBean 定义 id属性,值必须是 conversionService
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <ref bean="myDateConverter"/>
            </set>
        </property>
    </bean>
    
    • 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>
    

    后置处理 Bean

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

    后置处理 Bean 原理分析

    在这里插入图片描述
    程序员实现 BeanPostProcessor 接口中规定的两个方法:

    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }
    

    作用:Spring 创建完对象,并进行注入后,可以运行 Before ⽅法进行加工;

    • 通过方法的参数获得 Spring 创建好的对象,最终通过返回值交给 Spring 框架。
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
    

    作⽤:Spring 执行完对象的初始化操作后,可以运行 After ⽅法进行加工;

    • 通过方法的参数获得 Spring 创建好的对象,最终通过返回值交给 Spring 框架。

    实战中:很少处理 Spring 的初始化操作,没有必要区分 BeforeAfter。只需要实现其中一个,建议是 After 方法即可。

    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;
        }
    }
    
    1. Spring 配置文件中进行配置
    <bean id="myBeanPostProcessor" class="com.yusael.beanpost.MyBeanPostProcessor"/>
    

    细节: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;
    }
    
    展开全文
  • 前置++ 和 后置++

    2020-06-18 23:29:28
    这里也很好解释了为什么后置++在感觉上在语句执行完后才进行递增,其实在执行过程中只是对临时值进行处理,原有值已经递增了。 注意: 为什么在前置++时要实现返回引用,而后置++时却不用引用返回。 .
  • spring容器启动过程

    2020-10-27 03:01:58
    1.什么是BeanFactoryPostProcessor 叫做BeanFactory的后置处理器,和Bean的后置处理器对比理解。 BeanPostProcessor用来对Bean进行处理的, BeanFactoryPostProcessor用来对BeanFactory进行处理的。 2....
  • 上一篇我们说到了spring...无论spring1.0还是spring5.0,其核心思想都离不开容器的初始化,bean的注入,后置处理起的使用等等功能,那么spring后面的版本提供了很多复杂的功能,这对我们阅读源码有一定的影响,而sp
  • 这里主要以xml配置为例解析aop代理的具体生成过程。aop对目标对象的某个...其实就是在创建bean时,初始化完成后,进行后置处理得到的。(AbstractAutowireCapableBeanFactory 579行 exposedObject = initializeBea...
  • 概论 什么是建造者模式呢?将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。...第四步:后置处理,例如记录操作日志 最后核心的算法设计在run方法中。如下代码所示: 1 pu...
  • 1.4 什么是面向对象分析和设计 1.5 简短示例 1.6 什么是UML 1.7 可视建模的优点 1.8 历史 1.9 参考资料 第2章 迭代、进化和敏捷 2.1 什么是UP?其他方法能否对其进行补充 2.2 什么是迭代和进化式开发 2.3 ...
  • 1.5.3 组织中的角色是什么 1.5.4 谁该干什么?他们之间如何协作 1.6 面向对象的分析与设计的例子 1.6.l 定义用况 1.6.2 定义概念模型 1.6.3 定义协作图 1.6.4 定义设计类图 1.6.5 掷骰子游戏...
  • JAVA面试题最全集

    2010-03-13 13:09:10
    87.UNIX中QT是什么意思? 88.在软件开发生命周期中的哪个阶段开始测试? 89.dotnet与J2EE的比较? 90.什么是ActiveX? 91.Java中IDL是什么? 92.ISO9000和CMM是什么?IS09000和CMM(软件能力成熟度模型)认证是国际上...
  • 第1章 什么是面向对象编程 1 1.1 背景 1 1.1.1 面向过程编程示例 2 1.1.2 银行账户的表示 3 1.1.3 银行账户的安全 4 1.1.4 用面向对象编程解决问题 5 1.2 理解对象模型 7 1.3 术语 8 1.4 ...
  • Spring Boot由Pivotal团队提供的全新框架,其设计目的用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。用我的话来理解,就是Spring ...
  • 2.2 什么是变量 21 2.3 存储数值的变量 21 2.3.1 整数变量 21 2.3.2 变量的命名 25 2.3.3 变量的使用 26 2.3.4 变量的初始化 28 2.3.5 算术语句 28 2.4 变量与内存 34 2.5 整数变量类型 35 2.5.1 无符号的...
  • 2.2 什么是变量 21 2.3 存储数值的变量 21 2.3.1 整数变量 21 2.3.2 变量的命名 25 2.3.3 变量的使用 26 2.3.4 变量的初始化 28 2.3.5 算术语句 28 2.4 变量与内存 34 2.5 整数变量类型 35 2.5.1 无符号的...
  • 15.5.4 句柄是什么 294 15.5.5 显示图片 295 15.5.6 动画 299 15.5.7 键盘控制人物移动 303 15.5.8 迷宫墙壁 307 15.5.9 走迷宫 313 15.5.10 用链表记录行走路线 316 第16章 多态性 322 16.1 为什么要使用...
  • 8.1.1 XAML是什么 139 8.1.2 用C#模拟XAML实现的内容 141 8.1.3 XAML的种类 143 8.2 XAML基础 143 8.2.1 命名空间 144 8.2.2 代码后置文件 146 8.2.3 使用简单的属性和类型转换器 149 8.2.4 属性语法与属性元素语法 ...
  • 同时,这也一本有趣的计算机图书,作者用生动的语言、精巧的构思以及详尽的示例,定会使读者在学习模板编程的过程中体会到发现新风景的愉悦。对于C++语言进阶读者,强烈推荐本书。 —— 广州三星通信研究院 首席...
  • 14_成员函数和友元函数完成一元运算符重载(后置) 15_友元函数实现左移右移操作符重载(函数返回值当左值需返回引用)_传智扫地僧 16_友元函数实现操作符重载知识总结 17_重载等号操作符_传智扫地僧 18_数组类小案例_...

空空如也

空空如也

1 2
收藏数 21
精华内容 8
关键字:

后置处理过程是什么