您现在的位置是:首页 >学无止境 >Spring IOC - FactoryBean源码解析网站首页学无止境
Spring IOC - FactoryBean源码解析
1. 介绍
FactoryBean是Spring框架中的一个接口,它允许我们自定义一个工厂类,用于创建和管理Spring容器中的Bean实例。FactoryBean接口定义了两个方法:
- getObject():用于返回一个Bean实例,这个方法可以自定义创建Bean实例的逻辑。
- getObjectType():用于返回创建的Bean实例的类型。
当我们在Spring中自定义一个FactoryBean时,Spring容器会先创建这个FactoryBean实例,然后调用它的getObject()方法来获取实际的Bean实例。FactoryBean的使用场景比较广泛,例如:
- 当我们需要创建一个Bean实例时,但是这个Bean实例的创建过程比较复杂,需要进行一些额外的逻辑处理,这时我们可以使用FactoryBean来自定义创建过程。
- 当我们需要创建多个实例时,但是这些实例的创建逻辑比较相似,只有一些参数不同,这时我们可以使用FactoryBean来封装这些相似的逻辑,避免重复代码。
2. Demo
@Component
public class MyFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
public class FactoryBeanTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(FactoryBeanTest.class.getPackage().getName());
System.out.println(annotationConfigApplicationContext.getBean("&myFactoryBean"));
System.out.println(annotationConfigApplicationContext.getBean("myFactoryBean"));
}
}
返回结果如下:
3. 现象
- FactoryBean会创建两个对象
-
beanName为myFactoryBean,实例为自己本身,存储在单例池singletonObjects(一级缓存)中
-
通过getObject创建的对象,beanName为myFactory,缓存在factoryBeanObjectCache中,它是专门用来缓存通过FactoryBean创建的单例对象的。
-
上述两个单例池均为ConcurrentHashMap类型,属于Spring容器的一部分。
-
单例池和factoryBeanObjectCache中的beanName都为myFactory,没有&前缀,该前缀只是决定了从哪个缓冲池取对象
4. 源码解析
注:源码较长,只关注主干逻辑,省略了非主要代码
执行路径:main#getBean -》 AbstractApplicationContext#getBean -》 AbstractBeanFactory#doGetBean -》 AbstracBeanFactory#getObjectForBeanInstance -》 FactoryBeanRegistrySupport#getObjectFromFactoryBean -》FactoryBeanRegistrySupport#doGetObjectFromFactoryBean -》 FactoryBean#getObject
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 如果name以一个或多个&符合开头,则去掉该一个或多个&符号,否则直接返回
// 如果是别名,则转换成规范名称
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 从单例池中获取实例,在AnnotationConfigApplicationContext实例化后,此时
// 单例池中已有键值对:myFactoryBean:MyFactoryBean实例,所以能够获取到
Object sharedInstance = getSingleton(beanName);
// 接下来代码基本就是一个if-else分支
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 + "'");
}
}
// 获取给定bean实例的对象,可以是bean实例本身,也可以是FactoryBean创建的对象
// 下面会解析该方法
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// else分支在这里可以不用关注
}
return (T) bean;
}
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 如果bean实例是FactoryBean类型或者以&字符开头直接返回
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
// 从factoryBeanObjectCache缓冲池中获取对象
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获取对象,该方法继续调用doGetObjectFromFactoryBean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
// 回到factoryBean的getObject方法,返回的对象会缓存到factoryBeanObjectCache池子中
object = factory.getObject();
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}