第五天
反转控制(IOC Inverse of Control)和 依赖注入
反转控制(IOC Inverse of Control)
1.控制:对成员变量赋值的控制权
2.反转控制:把对于成员变量赋值的控制权,从代码中反转到Spring工厂和配置文件完成
3.好处:解耦合
4.底层实现:工厂模式
依赖注入
1.注入:通过Spring的工厂及配置文件,为对象的成员变量赋值
2.依赖注入:当一个类需要另一个类时,就意味着依赖,一旦依赖,就可以把另一个类作为本类的成员变量,最终通过Spring配置文件注入
3.好处:解耦合
Spring工厂创建复杂对象
什么是复杂对象
复杂对象:值得就是不能直接通过new构造方法创建对象比如Connection,SqlSessionFactory
Spring工厂创建复杂对象的三种方式
1.FactoryBean接口
(1)实现FactoryBean接口
package com.spring.context.basic;
import org.springframework.beans.factory.FactoryBean;
import java.sql.Connection;
import java.sql.DriverManager;
/**
* @author PitterWang
* @create 2020/5/30
* @since 1.0.0
*/
public class ConnectionFanctoryBean implements FactoryBean {
/**
* 业务代码
* @return
* @throws Exception
*/
@Override
public Object getObject() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo", "root", "manager1");
return connection;
}
/**
* 返回要返回的对象
* @return
*/
@Override
public Class<?> getObjectType() {
return Connection.class;
}
/**
* 是否创建多个对象
* @return
*/
@Override
public boolean isSingleton() {
return false;
}
}
(2)Spring配置文件的配置
<bean id = "conn" class="com.spring.context.basic.ConnectionFanctoryBean"/>
(3)使用
@org.junit.Test
public void test2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml"); @org.junit.Test
public void test2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
//com.mysql.jdbc.JDBC4Connection@1c39680d
Connection connection =(Connection) applicationContext.getBean("conn");
System.out.println(connection);
//com.spring.context.basic.ConnectionFanctoryBean@62833051
ConnectionFanctoryBean connectionFanctoryBean = (ConnectionFanctoryBean)applicationContext.getBean("&conn");
System.out.println(connectionFanctoryBean);
}
Connection connection =(Connection) applicationContext.getBean("conn");
System.out.println(connection);
}
说明:
①如果获得复杂对象就直接用applicationContext.getBean(“conn”);
如果想获得当前bean对象就用applicationContext.getBean("&conn");
②isSingleton方法,返回true只会创建一个复杂对象,返回false每次创建都会创建新的对象。
③Spring内部运⾏流程
1. 通过conn获得 ConnectionFactoryBean类的对象 ,进 ⽽通过instanceof 判断出是 FactoryBean接⼝的实现类
2. Spring按照规定 getObject() ---> Connection
3. 返回Connection
2.实例工厂
(1)创建复杂对象
package com.spring.context.basic;
import java.sql.Connection;
import java.sql.DriverManager;
/**
* 实例工厂
*
* @author PitterWang
* @create 2020/5/30
* @since 1.0.0
*/
public class ConnectionFanctoryNewBean {
public Connection getConnection() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo", "root", "manager1");
return connection;
}
}
(2)配置文件
<bean id = "fanctoryNewBean" class="com.spring.context.basic.ConnectionFanctoryNewBean"></bean>
<bean id="connew" factory-bean="fanctoryNewBean" factory-method="getConnection"/>
(3)使用
@org.junit.Test
public void test3(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
//com.mysql.jdbc.JDBC4Connection@7c214cc0
Connection connection =(Connection) applicationContext.getBean("connew");
System.out.println(connection);
}
3.静态工厂
(1)创建复杂静态方法
public static Connection getConnectionNew() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo", "root", "manager1");
return connection;
}
(2)配置文件
<bean id = "fanctorybb" class="com.spring.context.basic.ConnectionFanctoryNewBean" factory-method="getConnectionNew"/>
(3)使用
@org.junit.Test
public void test4(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
//com.mysql.jdbc.JDBC4Connection@7c214cc0
Connection connection =(Connection) applicationContext.getBean("fanctorybb");
System.out.println(connection);
}
创建对象次数
控制简单对象的创建次数
<bean id="pp" scope="singleton/prototype" class="com.spring.context.basic.Persion"/>
通过scope来控制
singleton:只会创建一次默认值
prototype:每一次都会创建新的对象
控制发杂对象的创建次数
public boolean isSingleton() {
return false; //每一次都会创建新的
return true; //只会创建一次
}
Spring 创建对象总结
对象的生命周期
什么是生命周期
指一个对象创建、存活、消亡的一个完整过程。
了解Spring负责对象的创建、存活、销毁,了解什么周期,有利于我们使用号Spring为我们创建的对象
生命周期的三个阶段
(1)创建阶段
scope = “singleton”
1.Spring 工厂创建的时候,对象就同时创建
2.如果配置lazy-init="true",获取对象的同时,创建对象
scope = “prototype”
获取对象的同时,创建对象
(2)初始化阶段
Spring工厂在创建完对象后,调用对象的初始化方法,完成对象的初始化操作
1.根据需求,提供初始化方法,完成初始化
2.初始化方法调用是Spring工厂自动调用
提供初始化方法的两种方式
①实现InitializingBean接⼝
1.实现InitializingBean接口
2.实现afterPropertiesSet方法
public class Teacher implements InitializingBean {
private Long id;
private String teacherName;
public Teacher() {
System.out.println("Teacher~~~~~");
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化~~~~~~~~~~~~");
}
}
②对象提供一个普通方法
1.写初始化方法
public void myInit(){
System.out.println("初始化2~~~~~~~~~~~~");
}
2.在配置文件种配置
<bean id="pp111" class="com.designpatterns.factory.test2.Teacher" init-method="myInit"/>
初始化说明:
1.如果一个对象两种方法都用了,初始化顺序是先完成InitializingBean接口方法,后自定义方法
2.注入一定反转在初始化之前
3.什么是初始化?资源初始化,比如IO,网络,数据库
(3)销毁阶段
Spring销毁对象之前,回调用对象的销毁方法,完成销毁操作
1.什么时候销毁所创建的对象?
ctx.close();的时候
2.销毁方法根据需求,定义销毁方法,完成销毁操作。调用时Spring去调用
提供销毁方法的两种方式
①实现DisposableBean接口
①对象实现DisposableBean接口
②实现destroy方法
@Override
public void destroy() throws Exception {
System.out.println("d销毁方法~~~~~~~~~~~~");
}
②自定义销毁方法
①写销毁方法
public void myDestroy(){
System.out.println("d销毁方法2~~~~~~~~~~~~");
}
②在配置文件中配置
<bean id="pp111" class="com.designpatterns.factory.test2.Teacher" init-method="myInit" destroy-method="myDestroy"/>
销毁方法说明
1.销毁方法只适用于scope=“singleton”
2.销毁方法主要用于资源释放。io.close()…
配置文件可参数化
把Spring配置⽂件中需要经常修改的字符串信息,转移到⼀个更⼩的配置⽂件中
(1)提供一个小的配置文件(.properities)
名字,位置随便方
jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/demo
jdbc.username = root
jdbc.password = manager1
(2)把配置文件引入到spring配置文件中
<context:property-placeholder location="classpath:/db.properties"/>
(3)在spring文件中通过${key }获取小配置文件的对应的值
<bean id = "fanctoryNewBean" class="com.spring.context.basic.ConnectionFanctoryNewBean">
<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>
自定义类型转换器
1.类型转换器
Spring 通过类型转换器把配置文件中字符串类型的数据,转换成了对象中成员变量的类型的数据,进而完成注入
2.自定义类型转换器
因为Spring内部没有提供特点类型转换器,所以有些转换器需要自己去定义
1.实现Converter接口,实现convert方法
public class MyDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd");
Date parse = null;
try {
parse = simpleDateFormat.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return parse;
}
}
2.配置文件中注册转换器
<bean id= "myDateConverter" class="com.spring.context.basic.converter.MyDateConverter"></bean>
<!--
id必须时conversionService
⽬的:告知Spring框架,我们所创建的MyDateConverter是⼀个类型转换器
-->
<bean id = "conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myDateConverter"/>
</set>
</property>
</bean>
后置处理Bean
(1)BeanPostProcessor,对Spring工厂所创建的对象进行再加工
(2)实现BeanPostProcessor接口,需要实现接口中的两个方法
//作用:Spring创建完对象,并进行注入后,可以运行Before方法进行加工
//获得Spring创建好的对象,通过方法的参数最终通过返回值交给Spring框架
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
//作⽤:Spring执⾏完对象的初始化操作后,可以运⾏After⽅法进⾏加⼯
//获得Spring创建好的对象 :通过⽅法的参数最终通过返回值交给Spring框架
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
(3)开发步骤
(1)后置Bean实现BeanPostProcessor接⼝
package com.spring.context.basic.beanPostProcessor;
import com.spring.context.basic.Persion;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* 〈〉
*
* @author PitterWang
* @create 2020/6/2
* @since 1.0.0
*/
public class BeanPostProcessBean implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Persion){
Persion persion = (Persion) bean;
persion.setName("wcdd");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Persion){
Persion persion = (Persion) bean;
persion.setName("qwert");
}
return bean;
}
}
(2)配置文件配置Bean
//配置到那个spring工厂,就会对Spring⼯⼚中所有创建的对象进⾏加⼯。
<bean class="com.spring.context.basic.beanPostProcessor.BeanPostProcessBean"/>