目录
1、FactoryBean的作用
一般情况下,Spring 通过反射机制利用 bean 的 class 属性获取实现类来实例化 bean。
Spring 还提供了一种定制实例化 bean的方案,Spring 为此提供了 FactoryBean 的工厂类接口。
FactoryBean 接口在Spring 中占有重要的地位,Spring自身提供了 70 多个 FactoryBean 实现。它们隐藏了实例化一些复杂 bean 的细节,给上层应用带来了便利。
package org.springframework.beans.factory;
import org.springframework.lang.Nullable;
public interface FactoryBean<T> {
/**
* 返回由 FactoryBean 创建的 bean 实例,如果为单例,则该 bean 会被缓存到 单实例缓存池中
*
*/
@Nullable
T getObject() throws Exception;
// 返回 FactoryBean 创建的 bean 类型
@Nullable
Class<?> getObjectType();
// 是否为单例
default boolean isSingleton() {
return true;
}
}
以下示例演示,FactoryBean 定制实例化bean的。
2、FactoryBean 的示例
被FactoryBean 创建的 bean
package thinking.in.spring.boot.samples.spring5.bean;
public class User {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
FactoryBean
package thinking.in.spring.boot.samples.spring5.factorybean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
import thinking.in.spring.boot.samples.spring5.bean.User;
public class UserFactoryBean implements FactoryBean<User> {
private String userInfo;
@Override
public boolean isSingleton() {
return true;
}
@Nullable
@Override
public User getObject() throws Exception {
User user = new User();
String[] arr = this.userInfo.split(",");
user.setId(Integer.parseInt(arr[0]));
user.setName(arr[1]);
return user;
}
@Nullable
@Override
public Class<?> getObjectType() {
return User.class;
}
public String getUserInfo() {
return userInfo;
}
public void setUserInfo(String userInfo) {
this.userInfo = userInfo;
}
}
Spring 配置
<!-- FactoryBean 示例 -->
<bean id="userFactoryBean" class="thinking.in.spring.boot.samples.spring5.factorybean.UserFactoryBean">
<property name="userInfo" value="2,FactoryBean实例化的User类"/>
</bean>
Spring启动类
package thinking.in.spring.boot.samples.spring5.bootstrap;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import thinking.in.spring.boot.samples.spring5.customlabel.CustomLabel;
import thinking.in.spring.boot.samples.spring5.bean.User;
public class XmlBeanFactoryBootstrap {
public static void main(String[] args) {
DefaultListableBeanFactory defaultListableBeanFactory = new XmlBeanFactory(new ClassPathResource("application-context.xml"));
/**
* FactoryBean
*/
User user = (User) defaultListableBeanFactory.getBean("userFactoryBean");
System.out.println("FactoryBean 实例化的User对象:" + user);
// 获取 UserFactoryBean
UserFactoryBean userFactoryBean = (UserFactoryBean) defaultListableBeanFactory.getBean("&userFactoryBean");
System.out.println(userFactoryBean);
}
}
运行结果
FactoryBean 实例化的User对象:User{id=2, name='FactoryBean实例化的User类'}
thinking.in.spring.boot.samples.spring5.factorybean.UserFactoryBean@7c0e2abd
3、分析
当调用 getBean("userFactoryBean") 时,Spring 通过反射机制发现 UserFactoryBean 实现了 FactoryBean 的接口,这时 Spring 容器就调用接口方法 UserFactoryBean#getObject 方法返回。
如果希望获取 UserFactoryBean 的实例,则用 getBean("&userFactoryBean")