FactoryBean
FactoryBean是一个接口,接口声明如下:
package org.springframework.beans.factory;
import org.springframework.lang.Nullable;
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
FactoryBean是一种工厂bean,与普通的bean不一样,FactoryBean是一种可以产生bean的 bean。
FactoryBean的示例
package com.morris.spring.entity;
import org.springframework.beans.factory.FactoryBean;
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User("morris", 18);
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
package com.morris.spring.demo.annotation;
import com.morris.spring.entity.UserFactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* FactoryBean的使用
*/
public class FactoryBeanDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserFactoryBean.class);
System.out.println(applicationContext.getBean("&userFactoryBean"));
System.out.println(applicationContext.getBean("userFactoryBean"));
System.out.println(applicationContext.getBean("userFactoryBean"));
}
}
运行结果如下:
com.morris.spring.entity.UserFactoryBean@1ec78b9
User(username=morris, age=18)
User(username=morris, age=18)
从运行结果可以得出以下两个结论:
-
UserFactoryBean会向Spring器中注入两个对象,一个名为&userFactoryBean,代表FactoryBean本身,一个名为userFactoryBean,代表FactoryBean的getObject()方法返回的对象。
-
UserFactoryBean的getObject()方法只有在使用时才会被调用,也就是只有在使用时才会完成实例化,然后添加到Spring容器中进行管理,有点类似于Bean的懒加载。
从上面的现象很容易会认为Spring的一级缓存singletonObjects容器中会存有两个对象,一个名为&userFactoryBean的FactoryBean对象,一个名为userFactoryBean的Dog对象,真的是这样吗?
FactoryBean的用途
我们常规的Bean都是使用Class的反射获取具体实例,如果Bean的获取过程比较复杂,那么常规的xml配置需要配置大量属性值,这个时候我们就可以使用FactoryBean,实现这个接口,在其getObject()方法中初始化这个bean。
使用场景:
- mybatis的MybatisSqlSessionFactoryBean
与BeanFactory的比较
-
BeanFactory是个bean工厂,是一个工厂类(接口), 它负责生产和管理bean的一个工厂,是ioc容器最底层的接口,是个ioc容器,是spring用来管理和装配普通bean的ioc容器(这些bean称为普通bean)。
-
FactoryBean是个bean,在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,是一个可以生产对象和装饰对象的工厂bean,由spring管理后,生产的对象是由getObject()方法决定的。
FactoryBean的初始化
Spring启动过程中会使用BeanFactoryPostProcesser收集要被Spring管理的类,封装为一个BeanDefinition,FactoryBean类也不例外。然后会遍历所有的BeanDefinition进行实例化和初始化。
DefaultListableBeanFactory#preInstantiateSingletons
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 遍历所有的BD,开始实例化
for (String beanName : beanNames) {
// 把父BD中的属性复制到子BD中
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
/**
* 不是抽象的,是单例的,不是懒加载的才能被实例化
*/
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// factoryBean的实例化
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 普通bean的实例化
getBean(beanName);
}
}
}
... ...
如果一个Bean实现了FactoryBean接口,跟普通Bean一样会调用getBean(),只不过会在beanName前面加上&。
AbstractBeanFactory#isFactoryBean
判断一个bean是否是FactroyBean。
org.springframework.beans.factory.support.AbstractBeanFactory#isFactoryBean(java.lang.String)
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
// 存在实例,就判断实例是不是FactoryBean的实例
return (beanInstance instanceof FactoryBean);
}
// No singleton instance found -> check bean definition.
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
// No bean definition found in this factory -> delegate to parent.
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
}
// 不存在实例,就判断BD中的class(targetType)是不是实现了FactoryBean
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
判断bean是否实现了FactoryBean接口。
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
Boolean result = mbd.isFactoryBean;
if (result == null) {
Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
mbd.isFactoryBean = result;
}
return result;
}
AbstractBeanFactory#doGetBean
创建FactoryBean实例,与普通Bean的创建过程是一致的。
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// 如果beanName是FactoryBean,那么beanName前面一定以&开头
// transformedBeanName会把name中的&去掉
String beanName = transformedBeanName(name);
... ...
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
org.springframework.beans.factory.BeanFactoryUtils#transformedBeanName
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
// 去掉&
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
从上面的源码中可以发现FactoryBean的初始化与普通的Bean的初始化流程基本一致,最后UserFactoryBean会缓存在Spring的一级缓存容器singletonObjects,beanName为userFactoryBean,而不是&userFactoryBean(在调用的过程中判断Bean是一个FactoryBean就会给beanName加上前缀&,但是在底层的调用过程中又将beanName中的&去除了)。
另外可以发现FactoryBean.getObject()方法并未被调用。
getObject()方法的调用
FactoryBean所生产的Bean只有在调用FactoryBean.getObject()方法时才会被创建,而FactoryBean.getObject()的调用发生在对FactoryBean.getObject()返回值类型的Bean的获取时,例如:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserFactoryBean.class);
System.out.println(applicationContext.getBean("&userFactoryBean")); // 获取FactoryBean本身
System.out.println(applicationContext.getBean("userFactoryBean")); // 触发FactoryBean.getObject()
System.out.println(applicationContext.getBean("userFactoryBean")); // 只会触发一次FactoryBean.getObject()
FactoryBean.getObject()方法的被调用过程如下:
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// 如果beanName是FactoryBean,那么beanName前面一定以&开头
// transformedBeanName会把name中的&去掉
String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 查询缓存
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 这里会对factoryBean进行特殊处理
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
... ...
当我们调用applicationContext.getBean(“userFactoryBean”),执行到上面的方法中时,会先根据userFactoryBean拿到一级缓存中的UserFactoryBean,然后执行getObjectForBeanInstance()方法,这里会对factoryBean进行特殊处理,而普通的bean就会直接返回。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 判断name是否已&开头
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 普通的bean直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 这里会从factoryBeanObjectCache中拿factorybean产生的对象
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 这里面会直接调用factorybean对象的getObject()
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
分析上面的代码:
- 此时参数为name=userFactoryBean,beanName=userFactoryBean,beanInstance=UserFactoryBean
- 所以前面的两个if都会进入。
- factoryBeanObjectCache中目前也没有,只有执行过一次getObject()方法后才会被缓存到factoryBeanObjectCache。
- 最后会调用UserFactoryBean.getObject()方法来实例化Bean,并缓存到factoryBeanObjectCache。
总结:
- spring一级缓存中会存储名为userFactoryBean的UserFactoryBean
- factoryBeanObjectCache中会存储名为userFactoryBean的User