复杂对象是相对于简单对象可以直接 new 出的对象。这种对象在 Spring 中不可以通过简单对象的创建方式来创建。下面我们将通过实现 FactoryBean 接口、实例工厂、静态工厂三种方法来创建。
FactoryBean 接口
Spring 提供 FactoryBean 接口并且提供了 getObject 方法是为了支持自定义工厂。通过实现这个和接口,可以在获取 Bean 的时候执行一些定制化的操作,如返回一个特定的实例,或者根据特定条件来决定为 singleton 或者 prototype 类型。
getObject 方法允许自定义 Bean 创建过程,可以在这力编写自己的逻辑来决定返回的对象。并且在 getObjectType 方法中设定返回对象的类型。
注意:在实现这个接口的时候在后面指定的泛型是在配置文件中获取的对象类型,而不是实现接口的类对象。
代码演示:
ConnectionFactoryBean implements FactoryBean<Connection> :
注: isSingleton() 设定返回对象是否为单例模式
package com.day2springInject.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 username;
private String password;
@Override
public Connection getObject() throws Exception {
Class.forName(driverClassName);
Connection conn = DriverManager.getConnection(url,username,password);
return conn;
}
@Override
public Class<?> getObjectType() {
return Connection.class;
}
@Override
public boolean isSingleton() {
return false;
}
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
applicaitonContext.xml :
<!-- 数据库连接。复杂对象的创建这里的对象是实现类的对象而不是调用类的 -->
<bean id="conn" class="com.day2springInject.factorybean.ConnectionFactoryBean">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/mp"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
TestSpring:
@Test
public void test12() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
Connection conn = (Connection) ctx.getBean("conn"); // 得到的是 Connection 对象
Connection conn2 = (Connection) ctx.getBean("conn"); // 测试 isSingleton
System.out.println(conn);
System.out.println(conn2);
}
运行截图:
如果想要获取到原类的对象需要在getBean中加上 &
@Test
public void test13() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
ConnectionFactoryBean conn = (ConnectionFactoryBean) ctx.getBean("&conn"); // 这样获得的不是实现类对象了 而是调用类对象
System.out.println(conn);
}
实例工厂
实例工厂是为了解决
整合遗留系统:在之前的项目中没有使用 Spring 的项目使用最常规的 new 的方式来实现,需要修改成 Spring 项目但是无法修改源码的情况下,我们只能通过添加配置的方法了实现。
避免 Spring 框架的耦合:
代码耦合度越低越好,但是这样创建项目会使返回对象类型依赖于创建类,所以我们要解除这种耦合。
原来的 Connction 类:
public class ConnectionFactory {
public Connection getConnection() {
Connection conn = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mp","root","123456");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
我们一看便知,这种创建放法在不让改变代码的前提下变成 Spring 项目并添加对象依赖,只能通过添加依赖的方法,我们需要操作如下两步:
1.添加 Connection 的依赖
我们想要获取连接对象必须先获取到他的类才可以进行下去,所以先将 Connction 注册进去。
<bean id="connFactory" class="com.day2springInject.factorybean.ConnectionFactory"/>
但是这样有问题存在,就是连接对象是依赖于 Connection 的,这样不就和 Spring 降耦合的理念违背了?而且使用效果不好,所以我们还需要将这个连接对象创建出来也就是 conn 对象。
<bean id="conn1" factory-bean="connFactory" factory-method="getConnection"></bean>
这里的 factory-bean 是将 “connFactory” 这恶鬼bean作为工厂来创建 conn1 这个对象,factory-method 指定了工厂方法,也就是说通过 connFactory 这个对象的 getConnection 方法来创建 conn1。
@Test
public void test14() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
Connection conn = (Connection) ctx.getBean("conn1");
System.out.println(conn);
}
静态工厂
静态工厂是为了创建静态方法中的返回对象的工厂,因为静态方法的调用相对于实例方法可以省略创建的一步,也就是直接通过类对象.方法来使用,也就是staticConnextionFactort.getConnection() 。如果在不修改代码的前提下想要变为 Spring 管理,也是只能通过添加配置的方式来注册。
<bean id="conn2" class="com.day2springInject.factorybean.StaticConnectionFactory" factory-method="getConnection"></bean>
可能你会好奇,都是创建对象,为什么静态工厂好像再还没创建出实例来就可以获取类的类型了。
应该可以这么理解,就是说在<bean>注册的时候,如果还没注册完成也就是没有到</bean>的时候是没有注册出对象的,而是获取到了Class类。所以这也就是实例对象为什么需要两步的原因,而静态对象少一步的原因。