1. 对象的生命周期
1.1 什么是对象的生命周期
生命周期指的是一个对象创建、存活、消亡的一个完整过程
1.2 为什么要学习对象的生命周期
由Spring负责对象的创建、存活、销毁,了解生命周期,有利于我们使用好Spring为我们创建的对象
1.3 生命周期的3个阶段
(重点掌握创建阶段,初始化操作和销毁操作用的比较少)
1.3.1创建阶段
Spring工厂何时创建对象?
- 如果对象只会被生产一次 scope=“singleton”
Spring会在工厂创建的同时完成对象的创建
注意:设置scope=singleton 这种情况下 也需要在获取对象的同时创建对象 可以通过懒初始化来实现“”
<bean id="account" scope="singleton" class="com.tcgroup.scope.Account" lazy-init="true"/>
- 如果对象会被多次创建 scope=“prototype”
Spring工厂会在获取对象的同时,创建对象
classPathXmlApplicationContext.getBean("");
1.3.2初始化阶段
Spring工厂在创建完对象后,调用对象的初始化方法,完成对应的初始化操作
1. 初始化方法提供:程序员根据需求,提供初始化方法,最终完成初始化操作
2. 初始化方法调用:Spring工厂进行调用
定义初始化方法
第一种形式:实现InitializingBean接口
这个接口是由Spring提供的(耦合了Spring框架),里面有一个afterPropertiesSet()方法,这个就是初始化方法,可以在里面做一些初始化操作
public class Account implements InitializingBean {
public Account (){
System.out.println("构造方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("调用初始化方法");
}
}
第二种形式:对象中提供一个普通的方法
public class Account {
public void myInit(){
System.out.println("调用初始化方法");
}
}
在配置文件中通过init-method属性声明这个方法作为初始化方法进行调用
<bean id="account" scope="singleton" class="com.tcgroup.scope.Account" init-method="myInit"/>
细节分析
- 如果一个对象即实现InitializingBean 同时又提供的 普通的初始化方法顺序
1. InitializingBean
2. 普通初始化方法

-
注入一定发生在初始化操作的前面,先执行注入 然后执行构造方法

-
什么叫做初始化操作
资源的初始化:数据库 IO 网络 .....
1.3.3 销毁阶段
Spring销毁对象前,会调用对象的销毁方法,完成销毁操作
1. Spring什么时候销毁所创建的对象?
classPathXmlApplicationContext.close();
2. 销毁方法:程序员根据自己的需求,定义销毁方法,完成销毁操作
调用:Spring工厂完成调用
定义销毁方法
第一种形式:实现DisposableBean接口
//销毁方法(释放资源)
@Override
public void destroy() throws Exception {
System.out.println("调用destroy销毁方法");
}

第二种形式:对象中提供一个普通的方法
public class Account {
public void myDestroy(){
System.out.println("调用myDestroy销毁方法");
}
}
在配置文件中通过destroy-method属性声明这个myDestroy方法作为销毁方法进行调用
<bean id="account" scope="singleton" class="com.tcgroup.scope.Account" init-method="myInit" destroy-method="myDestroy">
<property name="age" value="10"/>
</bean>

细节分析
- 如果一个对象即实现DisposableBean同时又提供的 普通的初始化方法顺序
2. DisposableBean
3. 普通初始化方法
- 销毁方法的操作只适用于 scope=“singleton”
如果scope=“prototype” 那么销毁方法将不起作用

- 什么叫做销毁操作
主要指的就是 资源的释放操作 io.close()
connection.close();
1.4 生命周期总结

2. 配置文件参数化
把Spring配置文件中需要经常修改的字符串信息,转移到一个更小的配置文件中
1. Spring的配置文件中存在需要经常修改的字符串?
存在 以数据库连接相关的参数为代表
2. 经常变化字符串,在Spring的配置文件中,直接修改
不利于项目维护(修改)
3. 转移到一个小的配置文件(.properties)
利于维护(修改)
配置文件参数化:利于Spring配置文件的维护(修改)
2.1 配置文件参数的开发步骤
- 提供一个小的配置文件(.properities)
名字:随便(考虑可读性即可 这里取得名字是db.properties)
放置位置:随便
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.31.174:3306/?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC
jdbc.userName=root
jdbc.psaaword=123456
- Spring的配置文件与小配置文件db.properties进行整合
classpath表示根目录 - 在Spring配置文件中通过${key}获取小配置文件中对应的值
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!-- Spring的配置文件与小配置文件进行整合 -->
<context:property-placeholder location="classpath:/db.properties"/>
<!-- 在Spring配置文件中通过${key}获取小配置文件中对应的值 -->
<bean id="conn" class="com.tcgroup.factory.ConnectionFactoryBean">
<property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="userName" value="${jdbc.userName}"/>
<property name="psaaword" value="${jdbc.psaaword}"/>
</bean>
</beans>
3.类型转换器
3.1 类型转换器
作用:Spring通过类型转换器把配置文件中字符串类型的数据,转换成了对象中成员变量对应类型的数据,进而完成了注入(Spring底层完成)

3.2. 自定义类型转换器
3.2.1需要自定义类型转换器原因:
当Spring内部没有提供特定类型转换器时,而程序员在应用的过程中还需要使用,那么就需要程序员自己定义类型转换器
例如 我们定义了一个类,有String name和Date brithday两个属性
public class Biaozi {
private String name;
private Date brithday;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBrithday() {
return brithday;
}
public void setBrithday(Date brithday) {
this.brithday = brithday;
}
@Override
public String toString() {
return "Biaozi{" +
"name='" + name + '\'' +
", brithday=" + brithday +
'}';
}
}
接下来通过注入的方式给这个累的对象赋值,然后尝试输出

结果是报错,提示不能将String类型转换成Date类型
3.2.2自定义类型转换器
- 自定义一个类 实现 Converter接口
import org.springframework.core.convert.converter.Converter;
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属性进行注入(赋值)
*/
@Override
public Date convert(String s) {
Date date=null;
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
date = simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
- 在Spring的配置文件中进行配置
<!-- MyDateConverter对象创建出来 -->
<bean id="myDateConverter" class="com.tcgroup.converter.MyDateConverter"/>
<!-- 类型转换器的注册 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<!-- 把刚刚注册的MyDateConverter对象,
添加到ConversionServiceFactoryBean的converters属性中去 -->
<ref bean="myDateConverter"/>
</set>
</property>
</bean>
这样就解决了上面不能将String类型转换成Date类型的报错

3.2.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;
}
@Override
public Date convert(String s) {
Date date=null;
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
date = simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
<!-- MyDateConverter对象创建出来 -->
<bean id="myDateConverter" class="com.tcgroup.converter.MyDateConverter">
<property name="pattern" value="yyyy-MM-dd"/>
</bean>
<!-- 类型转换器的注册 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<!-- 把刚刚注册的MyDateConverter对象,
添加到ConversionServiceFactoryBean的converters属性中去 -->
<ref bean="myDateConverter"/>
</set>
</property>
</bean>
- **ConversionSeviceFactoryBean 定义 id属性 值必须 conversionService **
(原本其他bean标签里面的ID值是随便取得 只要唯一即可, 但是class对象是ConversionSeviceFactoryBean,ID就必须是conversionService 且区分大小写) - Spring框架内置日期类型的转换器
日期格式:2020/05/01 (不支持 :2020-05-01)
4.后置处理Bean
注意:BeanPostProcessor是个接口,AOP编程的底层实现会体现其厉害之处
BeanPostProcessor作用:对Spring工厂所创建的对象,进行再加工。
后置处理Bean的运行原理分析:

程序员实现BeanPostProcessor规定接口中的方法
(两个方法都是default修饰的,默认实现):
Object postProcessBeforeInitiallization(Object bean String beanName)
作用:Spring创建完对象,并进行注入后,可以运行Before方法进行加工
通过方法的参数获得Spring创建好的对象,进行加工,
最终通过返回值交给Spring框架
Object postProcessAfterInitiallization(Object bean String beanName)
作用:Spring执行完对象的初始化操作后,可以运行After方法进行加工
通过方法的参数获得Spring创建好的对象,进行加工
最终通过返回值交给Spring框架
实战中:
由于很少处理Spring的初始化操作:所以大部分市县没有必要区分Before After。只需要实现其中的一个After方法即可
注意:
如果只操作了postProcessAfterInitiallizationr方法
postProcessBeforeInitiallization也还是需要return bean对象
4.1 开发步骤:
- 创建一个实体类用于测试(实际开发不用)
package com.tcgroup.entity;
public class Categroy {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Categroy{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
- 创建一个类实现 BeanPostProcessor接口
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("xiongjianren");
return categroy;
}
}
- Spring的配置文件中进行配置
<bean id="c" class="com.tcgroup.entity.Categroy">
<property name="id" value="10"/>
<property name="name" value="xiongerzi"/>
</bean>
<bean id="myBeanPostProcessor" class="com.tcgroup.beanpost.MyBeanPostProcessor"/>
在上面代码中 通过配置文件我们设置Categroy对象的name为xiongerzi, 但是我们通过后置处理bean吧名字设置成了xiongjianren,所以最终输出这个对象的name属性是xiongjianren。
4.2 BeanPostProcessor细节
BeanPostProcessor会对基于当前配置文件创建的Spring工厂中所有创建的对象进行加工(也就是当前XML文件里面生产出来的所有对象),而步骤处理里面涉及强制类型转换,如果这个工厂需要创建Categroy以外的其他对象, 强制类型转换时就会报错, 所以需要对后置处理步骤进行保护,对对象的类型进行判断。
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 {
if (bean instanceof Categroy){
Categroy categroy=(Categroy) bean;
categroy.setName("xiongjianren");
return categroy;}
return bean;
}
}
本文详细介绍了Spring框架中对象从创建到销毁的整个生命周期,包括创建、初始化和销毁三个阶段的具体操作,以及如何通过配置实现对象的自定义初始化和销毁。

880

被折叠的 条评论
为什么被折叠?



