复杂对象
什么是复杂对象?
简单对象:指可以直接通过new 构造方法创建的对象。
(反射的底层也是new)
复杂对象:指不能通过new构造方法创建的对象。
- Connection
- SqlSessionFactory
Spring工厂创建复杂对象的3中方式
1. FactoryBean 接口
开发步骤:
- 实现FactoryBean接口
- Spring配置文件的配置
实现FactoryBean接口
FactoryBean
接口里 有三个方法 需要实现
getObject
- 在里面写创建复杂对象的代码,并返回创建的 复杂对象。getObjectType
- 返回 所创建复杂对象的Class对象。isSingleton
- 返回boolean值。需要创建一次 - 返回true
,每一次调用都创建一个复杂对象 - 返回false
。
package com.youcan.facotrybean;
import org.springframework.beans.factory.FactoryBean;
import java.sql.Connection;
import java.sql.DriverManager;
public class ConnectionFactoryBean implements FactoryBean<Connection> {
@Override
public Connection getObject() throws Exception {
//用于书写创建复杂对象的代码,并把复杂对象作为方法的返回值 返回
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc://localhost:3306/adam","root", "mysql666");
return conn;
}
@Override
public Class<?> getObjectType() {
//返回 所创建复杂对象的Class对象
return Connection.class;
}
// 设置true:只需要创建一次 ,设置false: 每一次调用都创建一个复杂对象
@Override
public boolean isSingleton() {
return false;
}
}
Spring配置文件的配置
注意下返回值类型 (对比简单对象和复杂对象)
//复杂对象,通过FactoryBean接口的实现类ConnectionFactoryBean创建
<bean id="conn" class="com.youcan.factorybean.ConnectionFactoryBean">
//简单对象,通过Person直接创建
<bean id="person" class="com.gogogo.Person">
{这个地方 书写和 创建简单对象的书写格式是一样的
获得简单对象: ctx.getBean("person")
获得的是 Person类的一个对象。}
注意:我们不一样
FactoryBean
接口实现类是ConnectionFactoryBean
,通过ctx.getBean("conn")
获得的是它所创建的复杂对象 Connection
。
(创建ConnectionFactoryBean
这个类是为了得到 Connection
对象,所以‘ConnectionFactoryBean这个类的对象 显得并不重要‘。返回值不是ConnectionFactoryBean
这个类的对象。所以Spring对FactoryBean接口的实现类的返回指 做出了改变。)
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
Connection conn = (Connection) ctx.getBean("conn");
System.out.println("conn = " + conn);
//output
// conn = com.mysql.jdbc.JDBC4Connection@6329d432
小结:
如果Class中指定的类型是FactoryBean
接口的实现类,那么通过id值获得的是这个类所创建的复杂对象,即返回值是复杂对象。
Notice here
- 那么就行获得ConnectionFactoryBean对象,怎么做呢?
ctx.getBean("&conn")
加 & 符号,
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
ConnectionFactoryBean conn = (ConnectionFactoryBean) ctx.getBean("&conn");
System.out.println("conn = " + conn);
//output
// conn = com.youcan.factorybean.ConnectionFactoryBean@9529a423
isSingleton
方法
返回true, 只会创建一个对象
返回false,每次都会创建新的对象
问题:根据这个对象的特点,决定是返回true 或者false。
return true
SqlSessionFactory对象, 只创建一次就可以。
return false
Connection对象,不可公用,每次都需要重建。- mysql 高版本连接创建是,需要指定SSL证书,解决问题的方式:
url = "jdbc:mysql://localhost:3306/adam?useSSL=false"
- 依赖注入的体会(DI)
上一节有讲了,A依赖B,就可以把B作为成员变量,注入,解藕。
即将ConnectionFactoryBean中依赖的4个字符串,进行配置文件注入,步骤如下:
修改完如下:
package com.youcan.factorybean;
import org.springframework.beans.factory.FactoryBean;
import java.sql.Connection;
import java.sql.DriverManager;
public class ConnectionFactoryBean implements FactoryBean<Connection> {
private String driverClassName;
private String url;
private String user;
private String password;
//get set methods below
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 getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//用于书写创建复杂对象的代码, 即:连接对象
@Override
public Connection getObject() throws Exception {
Class.forName(driverClassName);
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}
//返回连接对象的class
@Override
public Class<?> getObjectType() {
return Connection.class;
}
//设置成true,只创建一次
@Override
public boolean isSingleton() {
return false;
}
}
配置文件中:
<bean id="conn" class="com.youcan.factorybean.ConnectionFactoryBean">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/adam?userSSl=false"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
FactoryBean 的实现原理(简易版)
- 接口回调
- 为什么Spring规定
FactoryBean
接口,要把创建复杂对象的代码写在getObject()
那个函数里? ctx.getbean("conn")
获得是复杂对象Connection
而没有获得ConnectionFactoryBean
?
- Spring 内部运行流程
- 通过
conn
获得ConnectionFactoryBean
类的对象,进而通过instanceof
判断出FactoryBean
接口的实现类 - Spring按照规定
getObject
—Connection
- 返回
Connection
FactoryBean
总结
Spring中用于创建复杂对象的一种方式,也是Spring原生提供的。
2. 实例工厂
为什么要用实例工厂?
- 避免Spring框架的侵入
- 整合遗留问题
开发步骤
当无法直接获得工厂代码时,我们可以通过创建实例工厂来获得功能。
factory-bean="connFactory"
factory-method="getConnection"
package com.youcan.factorybean;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionFactory {
public Connection getConnection(){
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/adam?userSSL=false", "root", "123456");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
}
创建工厂对象 connFactory
- 先创建connFactory实例工厂
- 再来调用getConnection方法
<bean id="connFactory" class="com.youcan.factorybean.ConnectionFactory"></bean>
<bean id="conn" factory-bean="connFactory" factory-method="getConnection"></bean>
测试实例工厂结果:
创建连接对象 conn
调用connFactory
工厂里的 getConnection
方法
public void Test5(){
//获取工厂
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
Connection conn = (Connection) ctx.getBean("conn");
System.out.println(conn);
}
3. 静态工厂
static主要体现在方法是static
在调用方法时可以直接使用
StaticConnectionFactory.getConnection()
(与实例工厂调用的区别)
配置文件:
//静态,创建对象,类名,方法
<bean id="conn" class="com.youcan.factorybean.StaticConnectionFactory" factory-method="getConnection"></bean>
spring 工厂创建对象的总结
学习快乐❤️
加加油~
“An essential part of creativity is not being afraid to fail.”
– Edwin H. Land