复杂对象是指无法使用 new
关键字直接创建的对象,比如在使用数据库连接的时候,我们需要用如下的方式创建对象:
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useSSL=false", "root", "root");
再比如在使用 MyBatis 时要获取 SQLSessionFactory
也是不能使用 new
直接创建的。
Spring为我们提供了一个 FactoryBean 接口,我们可以实现该接口,并重写方法来创建复杂对象。
public class MyFactoryBean implements FactoryBean<Connection> {
// 用于书写创建复杂对象
@Override
public Connection getObject() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
return DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useSSL=false", "root", "root");
}
@Override
public Class<?> getObjectType() {
return Connection.class;
}
// 是否单例
@Override
public boolean isSingleton() {
return false;
}
}
同时我们需要将该类加入到 Spring 容器中。
<bean class="edu.lsu.factorybean.MyFactoryBean" id="conn"/>
如果 class 中指定的类型是 FactoryBean 接口的实现类,那么通过 id 值获取的是这个类所创建的复杂对象。
ApplicationContext ac = new ClassPathXmlApplicationContext("/applicationContext.xml");
Connection conn = ac.getBean("conn", Connection.class);
System.out.println("conn = " + conn);
输出:
conn = com.mysql.jdbc.JDBC4Connection@4c40b76e
如果我们就像获取 FactoryBean
类型的变量,可以这样写:
ApplicationContext ac = new ClassPathXmlApplicationContext("/applicationContext.xml");
MyFactoryBean acBean = ac.getBean("&conn", MyFactoryBean.class);
System.out.println("acBean = " + acBean);
输出:
acBean = edu.lsu.factorybean.MyFactoryBean@5fcd892a
在 id 前面加上一个 &
号。
如果我们设置 isSingleton
的返回值为 true,那么多次获取的对象都是同一个,如果返回 false 则每次都会创建一个新的对象。
那么为什么 Spring 要定一个 FactoryBean
接口呢?
FactoryBean
接口就是一个接口回调。FactoryBean 的工作原理:
conn
获取 bean 对象,然后判断 instance(FactoryBean)
子类。getObject()
方法,创建复杂对象。由于实现 FactoryBean 接口会引起 Spring 框架的侵入,即一旦我们离开了 Spring,那么代码将不能使用。
至于为什么叫做实例工厂是因为只有再创建实例之后才能调用它的方法。
public class ConnectionFactory {
public Connection getConnection() {
Connection connection = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useSSL=false", "root", "root");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return connection;
}
}
同时需要在配置文件中配置如下信息:
<bean class="edu.lsu.factorybean.ConnectionFactory" id="connectionFactory"/>
<bean id="connection" factory-bean="connectionFactory" factory-method="getConnection"/>
静态工厂和实例工厂的区别就在于实例工厂的方法是实例方法,而静态工厂的方法是静态的。
public class StaticConnectionFactory {
public static Connection getConnection() {
Connection connection = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC&&useSSL=false", "root", "root");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return connection;
}
}
在配置文件上略有区别:
<bean class="edu.lsu.factorybean.StaticConnectionFactory" id="staticConnectionFactory" factory-method="getConnection"/>
静态工厂不需要创建对象就能调用方法,所以直接使用标签的属性即可。