Spring中级 IOC
1. 对象的生命周期
1.1什么是对象的声明周期
指的是一个对象创建、存活、消亡的一个完成过程
1.2.为什么学习对象的生命周期
由Spring负责对象的创建、存活、销毁。了解生命周期,有利于我们使用好Spring为我们创建的对象
1.3.生命周期的3个阶段
1.3.1创建阶段
Spring工厂何时创建对象
-
scope=“singleton”
Spring工厂创建的同时,对象的创建 注意:设置sope=singleton 也需要在获取对象的同时,创建对象,设置配置文件:layz-init
-
scope=“prototype”
Spring工厂会在获取对象的同时,创建对象 ctx.getBean("")
1.3.2初始化阶段
Spring工厂在创建完对象后,调用对象的初始化方法,完成对应的初始化操作
1.初始化方法提供:程序员跟据需求,提供初始化方法,最终完成初始化操作
2.初始化方法调用:Spring工厂进行调用
-
initializingBean接口
//初始化方法 //耦合了Spring框架 public void afterPropertiesSet()
-
对象中提供方法
public void myInit(){ } <bean id ="person" class="**.person" init-method="myInit"/>
细节:
-
如果都提供了两种方法,先执行接口初始化操作,在执行自定义初始化方法
-
当使用init-method 调用实现initializingBean接口的方法时,init-method会失效
-
注入发生在初始化之前
- 如果bean标签中还存在注入,则先执行注入,在执行初始化方法。所以接口方法名叫afterPropretiesSet 属性之后写入.
-
什么叫初始化操作
资源的初始化:数据库、IO、网络....
实际项目开发中 不常用
-
1.3.3销毁阶段
Spring销毁对象前,会调用对象的销毁的方法。完成销毁操作
1.Spring什么时候会销毁所创建的对象
ctx.close();
2.销毁方法,程序员定义的方法
调用:Spring工厂完成调用
-
disposableBean接口
@Override //实现销毁方法 public void destroy() throws Exception { System.out.println("OldPerson.destroy"); }
-
定义一个普通的销毁方法
@Override
public void myDestroy() throws Exception {
System.out.println("OldPerson.myDestroy");
}
<bean id ="person" class="**.person" destroy-method="destroy1"/>
细节分析
-
对象销毁只适用于 scope=“singleton”
-
原型对象不受Spring管理,单例对象保存在Spring中的一个单例map中。
-
什么叫做销毁操作
-
主要指的就是 资源的释放操作 io.close() connection.close()
-
当两种方式同时存在时,优先级为
1.disposableBean 2.destroy-method
-
实战中很少用
1.4总结
singleton 对象 默认在 spring工厂初始化时创建,如果需要在对象第一次调用时创建。则需在配置文件中配置 lazy-init
开启懒加载。
prototype对象在用户调用的时候创建。不受Spring控制,所以prototype不支持销毁操作
注入成员变量操作在对象初始化之前
2.配置文件参数化
把Spirng配置文件中需要经常修改的字符串信息,转移到更小的配置文件中
1.Spring的配置文件存在需要经常修改的字符串吗
存在:以数据库连接相关的参数 代表
2.什么场景需要配置文件参数化
经常修改的字符串
3.好与不好,在于维护好不好
运维工程师可能不懂java代码不懂spring。你要他如何在几千行的配置文件中找到要修改的字符串
不利于项目维护(修改)
4.转移到一个小的配置文件(properties)
2.1 配置文件参数化的开发步骤
2.1.1 提供一個小的配置文件 (properties)
名字可以随意
位置可以随意
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/userdb?useUnicode=utf-8&characterEncoding=utf-8serverTimezone=GMT%2B8useSSL=true
jdbc.username=root
jdbc.password=root
2.1.2 Spring配置文件与小配置文件的整合
<!--application.xml-->
<context:property-placeholder location="classpath:db.properties"/>
<!--Spring特有xml/yml
classpath: 代表类路径目录 spring会从这里去寻找一个指定的配置文件
classpath*: 代表类路根目录 Spring会从这里去寻找多个符合条件的配置文件。
-->
细节: classpath:不支持* 通配符。当location出现此符号时,此条配置作废,但不会抛出异常
2.1.3 在Spring配置文件中通过${key} 获取小配置文件中对应的值
<bean class="com.spring.factorybean.DruidDataSource" id="dataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
3 自定义类型转换器
3.1.类型转换器
作用:Spring通过类型转换器把配置文件中字符串类型的数据,转换成了对象中成员变量对应类型的数据,进而完成了注入
3.2 自定义类型转换器
原因:当Spring内部没有提供特定类型转换器时,而程序员在应用的过程中还需要使用,那么就需要程序员自己定义类型转换器
抛出异常:非法状态异常 :没有扫描到指定类型转换器。
原因:太难为spring了。每个国家的日期转换都不一样
-
中国: yyyy-MM-dd
-
美国:dd/MM/yyyy
sping并不知道你想要哪一种转换。所以自身不提供类型转换器。此时,便需要程序员自己配置
3.2.1 开发步骤
类 implements Converter 接口
/**
* convert 方法:Spring ---->LocalDateTime
DateTimeFormatter dtf = DateTimeFormatter.ofPatten("yyyy-MM-dd"); ---> LocalDateTime
param:source 代表的是配置文件中 日期字符串 <value>2020-10-11</value>
return:当把转换好的Date作为convert 方法的返回值后,Spring自动的为birthday 属性进行注入(赋值)
*
*/
public class MyDateConverter implements Converter<String, LocalDateTime> {
DateTimeFormatter dateTimeFormatter;
public void init(){
DateTimeFormatter.ofPattern("yyyy-MM-dd");
}
@Override
public LocalDateTime convert(String source) {
return LocalDateTime.parse(source,dateTimeFormatter);
}
}
在Spring的配置文件中进行配置
- 创建MyDateConverter Bean
<bean id ="myDateConverter" class="xxxx.myDateCOnverter"/>
- 创建转换服务工厂组件并注册(注入)类型转换器
目的:告知Spring框架 ,我们所创建的MyDateConverter是一个类型转换器
<!--用于注册类型转换器-->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="conversionService">
<property name="converters">
<set>
<ref bean="myDateConverter"/>
</set>
</property>
</bean>
细节
- MyDateConverter 中的日期的格式,通过依赖注入的方式,由配置文件完成赋值。
//MyDateConverter
public class MyDateConverter implements Converter<String, LocalDate> {
DateTimeFormatter dateTimeFormatter;
String datePattern;
public void setDatePattern(String datePattern) {
this.datePattern = datePattern;
}
public void init() {
dateTimeFormatter = DateTimeFormatter.ofPattern(datePattern);
}
@Override
public LocalDate convert(String source) {
return LocalDate.parse(source, dateTimeFormatter);
}
}
//Person
public class Person {
public String name;
private LocalDate birthday;
...
}
<!--application.xml-->
<context:property-placeholder location="classpath:date.properties"/>
<bean class="com.spring.converter.MyDateConverter" init-method="init" id="myDateConverter">
<property name="datePattern" value="${date.pattern}"/>
</bean>
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="conversionService">
<property name="converters">
<set>
<ref bean="myDateConverter"/>
</set>
</property>
</bean>
<bean class="com.spring.converter.Person" id="person">
<property name="name" value="菅江晖"/>
<property name="birthday" value="2002-07-24"/>
</bean>
# date.properties
date.pattern=yyyy-MM-dd
dateTime.pattern=yyyy-MM-dd HH:mm:ss
- ConverterServiceFactoryBean id必须为 conversionService
- 因为Spring是通过id来寻找转换服务工厂的,如果不存在id为conversionService 的转换工厂。spring默认啥也不做
Spring内置日期类型的转换器。
-
日期格式:2020/05/01(不支持:2020-05-01)
4 后置处理 Bean
BeanPostProcessor 对Spring工厂所创建的对象,进行在加工
AOP底层实现
注意:BeanPostProcessor 接口
xxxx(){
}
Spring工厂所创建的对象
BeanPostProcessor运行原理分析
程序员实现BeanPostProcessor接口中的方法:
Object postProcessorBeforeInitialization(Object bean ,String beanName)
作用:Spring创建完对象并进行注入后,可以运行Before方法进行加工
获得Spring创建好的对象:通过方法的参数
最终通过返回值交给Spring框架
Object postProcessorAfterInitializetion(Object bean,String beanName)
作用:Spring执行完对象的初始化操作后,可以运行after方法进行加工
获得Spring创建好的对象:通过方法的参数
最终通过返回值交给Spring框架
实战中:很少进行初始化操作,没有必要区分Before After,只需要其中的一个方法即可
注意:
postProcesserinitialization
return bean对象
4.1 BeanPostProcessor开发步骤
- 1 类实现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 {
//do thing
System.out.println(bean);
return bean;
}
}
- 2.Spring的配置文件中继续配置
<bean class="com.spring.beanpost.MyBeanPostProcessor" id="beanPostProcessor"/>
BeanPostProcessor 细节
BeanPostProcessor会对Spring工厂中所有创建的对象继续加工