1.IOC、DI、复杂对象 相关概念
1.1 控制反转 IOC
控制反转:把对于成员变量赋值的控制权,从代码中反转(转移)到Spring工厂和配置文件中完成
好处:解耦合
底层实现:工厂设计模式
1.2 依赖注入 DI
注入:通过Spring的工厂及配置文件,为对象(bean,组件)的成员变量赋值(get set)
依赖注入:当一个类需要另一个类的时候,就意味着依赖,,一旦出现依赖,就可以把另一个类作为本类的成员变量,最终通过Spring配置文件进行注入(赋值)
1.3 复杂对象
简单对象:可以直接通过new 构造方法创建的对象(Person)
复杂对象:不能直接通过new 构造创建的对象(sqlSessionFactory...),重量级资源
2.创建复杂对象的三种方式
2.1 FactoryBean接口
步骤:实现FactoryBean工厂,实现三个方法,在spring配置文件中配置
重点看后面实现的那三个方法
写一个ConnectionFactoryBean,实现接口:
2.1.1 依赖注入的体会
Class.forName(driverClassName);
Connection conn = DriverManager.getConnection(url,username,pwd);
创建Connection需要三个属性,这时就产生了依赖,通过配置注入到属性中,再进行使用,将程序的耦合度降低。
package zyc.stu.Spring5_34_44.FactoryBeanTest;
import java.sql.Connection;
import java.sql.DriverManager;
import org.springframework.beans.factory.FactoryBean;
/**
* @author zhuZiGe_
* @create 2020-09-10-9:30
*/
public class ConnectionFactoryBean implements FactoryBean<Connection> {
private String driverClassName;
private String url;
private String username;
private String pwd;
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
//实现三个方法
public Connection getObject() throws Exception {
Class.forName(driverClassName);
Connection conn = DriverManager.getConnection(url,username,pwd);
return conn;
}
public Class<?> getObjectType() {
return Connection.class;
}
public boolean isSingleton() {
return false;
}
}
xml文件配置:
<bean id="conn" class="zyc.stu.Spring5_34_44.FactoryBeanTest.ConnectionFactoryBean">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdemo?useSSL=false"/>
<property name="username" value="root"/>
<property name="pwd" value="root"/>
</bean>
测试:
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
Connection conn = (Connection) context.getBean("conn");
System.out.println(conn);
}
细节:
-
context.getBean("conn")
获得的是FactoryBean接口的泛型指定类:自动调用了重写的第一个方法getObject(),得到的是内部创建的复杂对象 -
isSingleton():控制了此复杂对象的创建次数
返回false:不是单例,每次创建新的对象 返回true:是单例,拿着上次创建的对象 ---------------------------------------------- 问题:什么时候返回ture? 根据需要,例如Connection,不能共用,每次都要创建新的连接,而SqlSessionFactory耗资源,只要一个就够了
-
FactoryBean的工作原理:context.getBean(“conn”)
首先,根据conn标签获得<bean>相关信息,并判断instanceof(FactoryBean)实现类 其次,根据判断结果,是FactoryBean的实现类,去找getObject方法 最后,调用getObject方法,将里面创建的复杂对象拿到
2.2 实例工厂
用途1:避免Spring框架的侵入(FactoryBean接口导致整个系统依赖于Spring)
用途2:整合遗留系统:
从现有的基础继续开发,没有源文件.java可供修改,只有编译好的.class文件时
没有源文件就无法实现FactoryBean接口
例:ConnectionFactory中是用的原始的方法实现复杂对象的创建,想得到复杂对象,必须实例化ConnectionFactory再调用getConnection方法,这时只需要在配置文件中集成这个遗留就行。
下面模拟一个遗留下来的实例:
先创建遗留实例的bean,将其纳入Spring管理,再创建新的bean,指明bean和想要调用的方法。</mark>
package zyc.stu.Spring5_34_44.FactoryBeanTest;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* @author zhuZiGe_
* @create 2020-09-10-12:35
*/
public class ConnectionFactory {
public Connection getConnection(){
Connection conn=null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/springdemo?useSSL=false","root","root");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
}
在xml文件中配置:我只想拿你内部那个方法获取复杂对象而已
<bean id="connFactory" class="zyc.stu.Spring5_34_44.FactoryBeanTest.ConnectionFactory"></bean>
<bean id="connSL" factory-bean="connFactory" factory-method="getConnection"/>
测试:
@Test
public void test2() {
ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
Connection connSL = (Connection) context.getBean("connSL");
System.out.println(connSL);
}
2.3 静态工厂
- 静态工厂和实例工厂大致相同,只不过工厂中的方法是静态的。
- 配置文件中,不用创建静态工厂的bean再去引用,直接使用class属性指定类,再指定调用的方法。
将上面的类名ConnectionFactory改为StaticConnectionFactory,并在方法上标记static,主要看xml文件中如何配置
<bean id="staticConnectionFactory" class="zyc.stu.Spring5_34_44.FactoryBeanTest.StaticConnectionFactory" factory-method="getConnection"/>
3.控制对象的创建次数
3.1 控制简单对象的创建次数
在配置文件中进行配置:
sigleton
:只会创建⼀次简单对象,默认值;
prototype
:每⼀次都会创建新的对象;
3.2 控制复杂对象的创建次数
通过isSingleton()方法控制:参考本文 2.1
public boolean isSingleton() { return true/false; }
3.3 如果是实例工厂或者静态工厂,没有 isSingleton ⽅法,与简单对象一样通过 scope 控制。
3.4 为什么要控制对象的创建次数
好处:节省不必要的内存浪费。
什么样的对象只创建⼀次?
- 重量级的、可以被共用的、线程安全的…
SqlSessionFactory | DAO | Service
什么样的对象每⼀次都要创建新的?
- 不能被共用的,线程不安全的…
Connection | SqlSession | Session
4.结尾
本文到这里就结束了,感谢看到最后的朋友,都看到最后了,点个赞再走啊,如有不对之处还请多多指正。
网友评论