前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring5学习笔记之工厂高级特性

Spring5学习笔记之工厂高级特性

作者头像
程序员Leo
发布2023-08-11 15:39:50
2060
发布2023-08-11 15:39:50
举报
文章被收录于专栏:Java知识点

# 1. 创建阶段

  • scope="singleton" 此时会在创建 Spring 工厂时,创建对象。 注意:如果同时设置了 lazy-init="true" ,那么会在获取对象 ctx.getBean("") 时创建。
  • scope="prototype" Spring 工厂会在获取对象时,创建对象,即调用 ctx.getBean("") 方法时创建。

注意:如果有属性需要注入 (DI),会在创建完成时立即进行注入。

# 2. 初始化阶段

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

程序员提供初始化方法的途径:

实现 InitializingBean 接口:

代码语言:javascript
复制
//实现这个方法,完成初始化操作
public void afterProperitesSet(){
  
}
  1. 对象中提供一个普通的方法同时配置 Spring 配置文件:
代码语言:javascript
复制
public void myInit(){
  
}

细节分析:

  • 如果一个对象即实现 InitializingBean,同时又提供的普通的初始化方法 ,顺序:
    1. InitializingBean
    2. 普通初始化方法
  • 注入一定发生在初始化操作的前面
  • 什么叫做初始化操作:资源的初始化:数据库、IO、网络 …
# 3. 销毁阶段

Spring 销毁对象 ctx.close(); 前,会调用对象的销毁方法,完成销毁操作

程序员定义销毁方法的途径:

实现 DisposableBean

代码语言:javascript
复制
public void destroy()throws Exception{
  
}

定义一个普通的销毁方法同时配置 Spring 配置文件:

代码语言:javascript
复制
public void myDestroy()throws Exception{

}
代码语言:javascript
复制
<bean id="" class="" init-method="" destroy-method="myDestroy"/>

细节分析:

  • 销毁方法的操作只适用于 scope="singleton"
  • 销毁操作主要指资源的释放操作,比如 io.close(); connection.close();

# 2. 配置文件参数化

# 2.1 什么是配置文件参数化

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

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

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

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

# 1. 提供一个小的配置文件
代码语言:javascript
复制
# 名字:随便
# 放置位置:随便

jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/test?useSSL=false
jdbc.username = root
jdbc.password = root
# 2. Spring 的配置文件与小配置文件进行整合
代码语言:javascript
复制
<context:property-placeholder location="classpath:/db.properties"/>
# 3. 在 Spring 配置文件中通过 ${key} 获取小配置文件中对应的值

# 3. 自定义类型转换器

# 1. 什么是类型转换器

Spring 提供了一种 Converter(类型转换器)的类型转换工具。在 Spring MVC 中,它的作用是在控制器方法对请求进行处理前,先获取到请求发送过来的参数,并将其转换为控制器方法指定的数据类型,然后再将转换后的参数值传递给控制器方法的形参,这样后台的控制器方法就可以正确地获取请求中携带的参数了。

Spring MVC 框架默认提供了许多内置的类型转换器,主要包括以下几种类型。

# 1.1 标量转换器

名称

作用

StringToBooleanConverter

String 到 boolean 类型转换

ObjectToStringConverter

Object 到 String 转换,调用 toString 方法转换

StringToNumberConverterFactory

String 到数字转换(例如 Integer、Long 等)

NumberToNumberConverterFactory

数字子类型(基本类型)到数字类型(包装类型)转换

StringToCharacterConverter

String 到 Character 转换,取字符串中的第一个字符

NumberToCharacterConverter

数字子类型到 Character 转换

CharacterToNumberFactory

Character 到数字子类型转换

StringToEnumConverterFactory

String 到枚举类型转换,通过 Enum.valueOf 将字符串转换为需要的枚举类型

EnumToStringConverter

枚举类型到 String 转换,返回枚举对象的 name 值

StringToLocaleConverter

String 到 java.util.Locale 转换

PropertiesToStringConverter

java.util.Properties 到 String 转换,默认通过 ISO-8859-1 解码

StringToPropertiesConverter

String 到 java.util.Properties 转换,默认使用 ISO-8859-1 编码

# 1.2 集合、数组相关转换器

名称

作用

ArrayToCollectionConverter

任意数组到任意集合(List、Set)转换

CollectionToArrayConverter

任意集合到任意数组转换

ArrayToArrayConverter

任意数组到任意数组转换

CollectionToCollectionConverter

集合之间的类型转换

MapToMapConverter

Map 之间的类型转换

ArrayToStringConverter

任意数组到 String 转换

StringToArrayConverter

字符串到数组的转换,默认通过 “,” 分割,且去除字符串两边的空格(trim)

ArrayToObjectConverter

任意数组到 Object 的转换,如果目标类型和源类型兼容,直接返回源对象;否则返回数组的第一个元素并进行类型转换

ObjectToArrayConverter

Object 到单元素数组转换

CollectionToStringConverter

任意集合(List、Set)到 String 转换

StringToCollectionConverter

String 到集合(List、Set)转换,默认通过 “,” 分割,且去除字符串两边的空格(trim)

CollectionToObjectConverter

任意集合到任意 Object 的转换,如果目标类型和源类型兼容,直接返回源对象;否则返回集合的第一个元素并进行类型转换

ObjectToCollectionConverter

Object 到单元素集合的类型转换

Spring MVC 对于基本类型(例如 int、long、float、double、boolean 以及 char 等)已经做好了基本类型转换。因此,通常情况下 Spring MVC 提供的这些类型转换器可以满足开发人员大多数的类型转换需求的。

注意:在使用内置类型转换器时,请求参数输入值需要与接收参数类型相兼容,否则会报 400 错误。

# 2. 类型转换器的作用

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

# 3. 为什么要自定义类型转换器?

原因:实际应用中需要转换某种特定的类型,且 Spring 内部没有提供这种类型转换器时,需要程序员自己定义。

# 4. 自定义类型转换器的开发步骤

# 4.1 实现 Converter<> 接口

代码语言:javascript
复制
public class MyDateConverter implements Converter<String, Date> {
    /*
    convert方法作用:String --->  Date
                   SimpleDateFormat sdf = new SimpleDateFormat();
                   sdf.parset(String) ---> Date
    param:source 代表的是配置文件中 日期字符串 <value>2020-10-11</value>

    return : 当把转换好的Date作为convert方法的返回值后,Spring自动的为birthday属性进行注入(赋值)

    */
    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;
    }
}

# 4.2 在 Spring 的配置文件中进行配置

代码语言:javascript
复制
<!-- 创建自定义转换器对象 -->
<bean id="myDateConverter" class="com.yuziyan.converter.MyDateConverter"/>

<!-- 在Spring中注册自定义的转换器 -->
<!-- 目的:告知Spring框架,我们所创建的MyDateConverter是一个类型转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <ref bean="myDateConverter"/>
        </set>
    </property>
</bean>

<!-- 上面两步完成之后就可以直接使用了 -->

# 5. 细节

# 5.1 体会依赖注入 (DI)

MyDateConverter 中的日期的格式,可以通过依赖注入的方式,由配置文件完成赋值。

代码语言:javascript
复制
public class MyDateConverter implements Converter<String, Date> {

    private String pattern;
    
    public String getPattern() { return pattern; }
    
    public void setPattern(String pattern) { this.pattern = pattern; }

    /*
        convert方法作用:String --->  Date
                       SimpleDateFormat sdf = new SimpleDateFormat();
                       sdf.parset(String) ---> Date
        param:source 代表的是配置文件中 日期字符串 <value>2020-10-11</value>

        return : 当把转换好的Date作为convert方法的返回值后,Spring自动的为birthday属性进行注入(赋值)

        */
    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;
    }
}
<!--创建自定义类型转换器对象-->
<bean id="myDateConverter" class="com.yuziyan.converter.MyDateConverter">
    <property name="pattern" value="yyyy-MM-dd"/>
</bean>

# ConversionSeviceFactoryBean 定义 id 属性,值必须是 conversionService

5.2 Spring 框架内置日期类型的转换器

日期格式:2020/05/01 (不支持 :2020-05-01)

# 6. 后置处理 Bean

# 6.1 BeanPostProcessor 的作用:

对 Spring 工厂所创建的对象,进行再加工。 注意:BeanPostProcessor 是接口

# 1. BeanPostProcessor

都是在目标对象被实例化之后,并且属性也被设置之后调用的

  • postProcessBeforeInitialization
    • 在 afterPropertiesSet 或者自定义的初始化方法 (使用 @bean 注解中的 initMethod () 属性或者使用 xml 配置) 之前执行
  • postProcessAfterInitialization
    • 在 afterPropertiesSet 或者自定义的初始化方法之后执行(如果是从 FactoryBean 中获取的对象,则只有这个方法会起作用,,postProcessBeforeInitialization 以及 afterPropertiesSet 或者自定义的初始化方法都不会有作用)
# 2. InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor 接口继承 BeanPostProcessor 接口,它内部提供了 3 个方法,再加上 BeanPostProcessor 接口内部的 2 个方法,所以实现这个接口需要实现 5 个方法。InstantiationAwareBeanPostProcessor 接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置

在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean () 方法的 Object bean = resolveBeforeInstantiation (beanName, mbdToUse); 方法里面执行了这个后置处理器

  • postProcessBeforeInstantiation
    • 在目标对象实例化之前调用,方法的返回值类型是 Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例 (一般都是代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有 postProcessAfterInitialization 方法会调用,其它方法不再调用;否则按照正常的流程走
  • postProcessAfterInstantiation
    • 方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是 null。如果该方法返回 false,会忽略属性值的设置;如果返回 true,会按照正常流程设置属性值。
  • postProcessPropertyValues
    • 方法对属性值进行修改 (这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果 postProcessAfterInstantiation 方法返回 false,该方法不会被调用。可以在该方法内对属性值进行修改
  • postProcessBeforeInitialization&postProcessAfterInitialization
    • 父接口 BeanPostProcessor 的 2 个方法
# 3. SmartInstantiationAwareBeanPostProcessor

智能实例化 Bean 后置处理器(继承 InstantiationAwareBeanPostProcessor)

  • determineCandidateConstructors
    • 检测 Bean 的构造器,可以检测出多个候选构造器 (Java 好像只会确定唯一的备选的构造器)
  • getEarlyBeanReference
    • 循环引用的后置处理器,这个东西比较复杂, 获得提前暴露的 bean 引用。主要用于解决循环引用的问题,只有单例对象才会调用此方法
  • predictBeanType
    • 预测 bean 的类型,在最后的类型转化时会用到
# 4. MergedBeanDefinitionPostProcessor
  • postProcessMergedBeanDefinition
    • 缓存 bean 的注入信息的后置处理器,仅仅是缓存或者干脆叫做查找更加合适,没有完成注入,注入是另外一个后置处理器的作用(不实现这个方法,也能直接调用 postProcessPropertyValues 完成属性值的注入)
# 5. DestructionAwareBeanPostProcessor
  • postProcessBeforeDestruction
    • 在 bean 实例被销毁之前被调用

# 6.2 后置处理 Bean 的运行原理分析

程序员实现 BeanPostProcessor 规定接口中的方法: 参数一:Spring 工厂创建好的对象 参数二:对象名字 返回值:返回的对象会交给 Spring 框架 Object postProcessBeforeInitiallization (Object bean String beanName) 作用:Spring 创建完对象,并进行注入后,会运行 Before 方法进行加工 Object postProcessAfterInitiallization(Object bean String beanName) 作用:Spring 执行完对象的初始化操作后,会运行 After 方法进行加工 实战中: 很少处理 Spring 的初始化操作:没有必要区分 Before After。只需要实现其中的一个 After 方法即可 注意: postProcessBeforeInitiallization(){ return bean 对象 }

# 6.3 BeanPostProcessor 的开发步骤

# 1. 实现 BeanPostProcessor 接口
代码语言:javascript
复制
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        Categroy categroy = (Categroy) bean;
        categroy.setName("xiaowb");


        return categroy;
    }
}
# 2. Spring 的配置文件中进行配置
代码语言:javascript
复制
<bean id="myBeanPostProcessor" class="xxx.MyBeanPostProcessor"/>
# 3. BeanPostProcessor 细节

BeanPostProcessor 会对 Spring 工厂中所有创建的对象进行加工。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 1. 创建阶段
    • # 2. 初始化阶段
      • # 3. 销毁阶段
      • # 2. 配置文件参数化
        • # 2.1 什么是配置文件参数化
          • # 2.2 配置文件参数化的开发步骤:
            • # 1. 提供一个小的配置文件
            • # 2. Spring 的配置文件与小配置文件进行整合
            • # 3. 在 Spring 配置文件中通过 ${key} 获取小配置文件中对应的值
        • # 3. 自定义类型转换器
          • # 1. 什么是类型转换器
            • # 1.1 标量转换器
            • # 1.2 集合、数组相关转换器
          • # 2. 类型转换器的作用
            • # 3. 为什么要自定义类型转换器?
            • # 4. 自定义类型转换器的开发步骤
              • # 4.1 实现 Converter<> 接口
                • # 4.2 在 Spring 的配置文件中进行配置
                • # 5. 细节
                  • # 5.1 体会依赖注入 (DI)
                  • # 6. 后置处理 Bean
                    • # 6.1 BeanPostProcessor 的作用:
                      • # 1. BeanPostProcessor
                      • # 2. InstantiationAwareBeanPostProcessor
                      • # 3. SmartInstantiationAwareBeanPostProcessor
                      • # 4. MergedBeanDefinitionPostProcessor
                      • # 5. DestructionAwareBeanPostProcessor
                    • # 6.2 后置处理 Bean 的运行原理分析
                      • # 6.3 BeanPostProcessor 的开发步骤
                        • # 1. 实现 BeanPostProcessor 接口
                        • # 2. Spring 的配置文件中进行配置
                        • # 3. BeanPostProcessor 细节
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档