Spring源码分析之FactoryBean原理及使用
前言
FactoryBean可以看做一个工厂Bean,它的getObject()方法可以生产另外一个Bean,且生产的Bean也由Spring管理。
简单使用
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
public class TestFactoryBean {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(UserServiceFactoryBean.class);
definitionBuilder.addPropertyValue("username", "lisi");
beanFactory.registerBeanDefinition("userService", definitionBuilder.getBeanDefinition());
UserService userService = (UserService) beanFactory
.getBean("userService");
System.out.println(userService.getUsername());//lisi
UserServiceFactoryBean userServiceFactoryBean = (UserServiceFactoryBean) beanFactory
.getBean("&userService");
System.out.println(userServiceFactoryBean.username);//lisi
}
public static class UserServiceFactoryBean implements FactoryBean<UserService> {
private String username;
public void setUsername(String username) {
this.username = username;
}
@Override
public UserService getObject() {
UserService userService = new UserService();
userService.setUsername(username);
return userService;
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
}
@Setter
@Getter
public static class UserService {
private String username;
}
}
我们定义一个UserServiceFactoryBean,用来生产UserService,将其注册到BeanFactory中,如果使用UserService对象,使用userService
的Bean名称,
如果想要获取原来的UserServiceFactoryBean对象,需要使用&userService
的Bean名称,&
这个前缀是Spring规定的,可以查看BeanFactory的FACTORY_BEAN_PREFIX常量。
原理分析
关于Bean大概的创建过程,Spring源码分析之Bean生命周期 已经介绍的差不多了,
这次在它的基础上我们来分析Spring对FactoryBean的处理。先进入AbstractBeanFactory的doGetBean()方法。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//处理FactoryBean类型的Bean名称,去除FactoryBean的前缀,如果name为&userService,处理之后为userService
//其实这一步还会处理Bean别名,如果userService的别名为userServiceAlias,name为userServiceAlias,处理之后为原来的userService(根据别名查找到原来的Bean名称)
final String beanName = transformedBeanName(name);
Object bean;
//查看是否已经创建过(从单例池中查询)
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//处理FactoryBean相关,核心方法
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
try {
//创建单例Bean
if (mbd.isSingleton()) {
//创建完成之后会将Bean放到单例池中,下次直接从池中取就可以了
sharedInstance = getSingleton(beanName, () -> {
try {
//真正创建Bean的地方,这一步是创建的FactoryBean自己,这里就是UserServiceFactoryBean对象。
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//销毁Bean
destroySingleton(beanName);
throw ex;
}
});
//处理FactoryBean相关
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
}
return (T) bean;
}
创建FactoryBean工厂生产的对象核心方法为getObjectForBeanInstance(),继续跟进去,注意AbstractAutowireCapableBeanFactory(AbstractBeanFactory的子类)重写了此方法
@Override
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//处理依赖相关,暂时不管
String currentlyCreatedBean = this.currentlyCreatedBean.get();
if (currentlyCreatedBean != null) {
registerDependentBean(beanName, currentlyCreatedBean);
}
//这里又进入了父类的getObjectForBeanInstance()方法,核心方法
return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
}
进入父类(AbstractBeanFactory)的getObjectForBeanInstance()方法
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//判断是否以前缀&开头,如果以&开头,说明获取的Bean是FactoryBean自身对象,beanInstance此时就是FactoryBean类型,原因看总结
if (BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
//此时beanInstance一定就是FactoryBean类型
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
//mbd不为null说明此时是第一次创建FactoryBean生产的对象
mbd.isFactoryBean = true;
}
else {
//直接从缓存中取
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
//调用FactoryBean的getObject()方法生产对象
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
继续getObjectFromFactoryBean()方法,真正生产另一个Bean对象的地方
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
//调用getObject()方法生产另一个对象
object = doGetObjectFromFactoryBean(factory, beanName);
//处理循环引用相关,所以又get()一次,暂时不管
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
//此方法为AbstractAutowireCapableBeanFactory重写,应用BeanPostProcessor的postProcessAfterInitialization()方法
//在Bean初始化之后做一些事情
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
//处理非单例情况,每次都创建一个,不保存到factoryBeanObjectCache中
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
}
return object;
}
}
从上面一个方法可以看到,对于FactoryBean生产的另一个Bean(这里就是UserService),是不走默认的初始化流程的(属性装配,Aware钩子回调,initMethod方法回调),
不会处理@Autowired,@Value注解。
原理总结
正常的Bean实例(非FactoryBean生产)是存储在DefaultSingletonBeanRegistry的singletonObjects属性中(IOC容器的底层实现),
而FactoryBean生产的对象是存储在FactoryBeanRegistrySupport的factoryBeanObjectCache属性中,这两个类都是DefaultListableBeanFactory的父类。
以上述例子来说,Bean名称&userService
对应的Bean类型为UserServiceFactoryBean,存储在singletonObjects(单例池,是一个Map)中(会处理Bean名称,去除&前缀,所以这里存储的key也是userService),
Bean名称userService
对应的Bean类型为UserService,存储在factoryBeanObjectCache中。
- getBean("userService")的流程: 查询singletonObjects得到Bean实例(如果没有就创建并保存到singletonObjects中),请求的Bean名称没有以
&
开头,且对象类型为FactoryBean,调用FactoryBean的getObject()生成对象,并保持到factoryBeanObjectCache缓存中,后续直接从缓存中取。 - getBean("&userService")的流程: 根据处理后的name(去除
&
前缀)查询singletonObjects得到Bean实例(如果没有就创建并保存到singletonObjects中),请求的Bean名称以&
开头,直接返回对象。
使用场景
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
public class TestFactoryBean2 {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//注册UserMapper
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MapperFactoryBean.class);
definitionBuilder.addPropertyValue("mapperInterface", UserMapper.class);
beanFactory.registerBeanDefinition("userMapper", definitionBuilder.getBeanDefinition());
//注册AddressMapper
definitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MapperFactoryBean.class);
definitionBuilder.addPropertyValue("mapperInterface", AddressMapper.class);
beanFactory.registerBeanDefinition("addressMapper", definitionBuilder.getBeanDefinition());
UserMapper userMapper = (UserMapper) beanFactory.getBean("userMapper");
System.out.println(userMapper.getCount());
AddressMapper addressMapper = (AddressMapper) beanFactory.getBean("addressMapper");
System.out.println(addressMapper.getCount());
}
public static class MapperFactoryBean<T> implements FactoryBean<T> {
private Class<T> mapperInterface;
public void setMapperInterface(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
@Override
public T getObject() {
//使用JDK动态代理创建对象
return (T) Proxy
.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface},
new MapperProxy());
}
@Override
public Class<?> getObjectType() {
return mapperInterface;
}
}
public static class MapperProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + " invoked");
return null;
}
}
interface UserMapper {
Integer getCount();
}
interface AddressMapper {
Integer getCount();
}
}
定义一个FactoryBean,可以根据不同的接口类型创建不同的实现,Mybatis的MapperFactoryBean和SpringDataJPA的JpaRepositoryFactoryBean就是这样实现的,
所以FactoryBean适用于创建一类相似且统一的Bean对象,且创建过程比较复杂。FactoryBean作为一个工厂Bean,如果只是创建一个或者很少的对象,确实没有使用的必要,
只有需要创建大量的对象的情况(可以类比现实中的工厂),才能体现出优势。