Spring源码之FactoryBean解析
文章目录
1. FactoryBean是什么
FactoryBean是一个工厂Bean,可以生成某一个类型Bean实例,它最大的一个作用是:可以让我们自定义Bean的创建过程。BeanFactory是Spring容器中的一个基本类也是很重要的一个类,在BeanFactory中可以创建和管理Spring容器中的Bean,它对于Bean的创建有一个统一的流程。
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的功能,在getObject
里面可以自定义实例对象,getObjectType
返回我们自定义实例对象的类型,isSingleton
是否单例,默认为true。
2. 如何得到FactoryBean本身实例
在容器启动过程中,会调用beanFactory.preInstantiateSingletons();
这个方法进行实例化bean,我们看看在循环实例化beanDefinitionNames
容器中的BeanDefinition
时,Spring是怎么做的
for (String beanName : beanNames) {
//把父BeanDefinition里面的属性拿到子BeanDefinition中
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//如果是非抽象的,单例的,非懒加载的就实例化
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//判断bean是否实现了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 {
//主要从这里进入,看看实例化过程
getBean(beanName);
}
}
}
在这里会判断所要实例化的bean是否是工厂bean,如果是FactoryBean
,调用getBean
的时候,在参数beanName的要加上前缀&
,由此我们可以得出结论:获取工厂bean本身需要在beanName的前面加上前缀&
那么在getBean
里面又是怎么做的呢String beanName = transformedBeanName(name);
这里有两个变量:beanName
,name
如果是工厂bean,那么name = & + beanName
,这两个变量也是作为FactoryBean接口的调用入口的重要参数来使用的bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
我们来看看这个方法
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.
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;
}
}
这个方法很简单,如果是工厂bean,则返回工厂bean本身
3. 如何得到FactoryBean中的自定义对象实例
使用FactoryBean对象个性化对象创建,因为对象是在工厂bean里面创建的,不是直接暴露给Spring的,所以需要我们手动调用才会进行对象的创建。
假设我们在FactoryBean
中创建了一个Student
对象,那么我们需要得到Student
对象,需要借助上下文对象
Student bean = applicationContext.getBean(Student.class);
我们来看看其中的重点方法resolveNamedBean
,进过断点调试,在方法上写上注释
//candidateNames里面装的是Student的工厂bean标识
String[] candidateNames = getBeanNamesForType(requiredType);
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
//这里调用getBean返回的是Student对象
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
}
看到这里自然就会有两个疑问,为什么入参是Student,拿到的确是工厂bean,getBean传入的是共产bean标识,拿到的确是Student对象呢,我们分别来看看这两个方法都做了什么
3.1. 首先我们先来看看getBeanNamesForType
//循环所有的beanDefinition
for (String beanName : this.beanDefinitionNames) {
//判断是否是工厂方法
boolean isFactoryBean = isFactoryBean(beanName, mbd);
if (isFactoryBean) {
if (includeNonSingletons || isNonLazyDecorated ||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
//这个是主要方法,用来找到能够实例化Student的工厂bean
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
if (matchFound) {
//匹配的beanName加入到集合中返回
result.add(beanName);
}
}
}
重点来看看isTypeMatch
方法
String beanName = transformedBeanName(name);
boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
// Check manually registered singletons.
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
if (beanInstance instanceof FactoryBean) {
if (!isFactoryDereference) {
//前面都是判断条件:如果是工厂bean,且不带&前缀,进入这个方法
Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
//判断工厂中的实例化类型和我们要得到的实例是不是保持一致
return (type != null && typeToMatch.isAssignableFrom(type));
}
}
}
那么getTypeForFactoryBean
这个方法又做了什么呢
protected Class<?> getTypeForFactoryBean(FactoryBean<?> factoryBean) {
//看到的是调用了工厂bean中的getObjectType方法,这也是FactoryBean接口中的三个方法之一
return factoryBean.getObjectType();
}
3.2. (T) getBean(beanName, requiredType.toClass(), args)
Object sharedInstance = getSingleton(beanName);
//这里在缓存中一定能拿到bean工厂实例,因为在容器启动过程中已经将工厂bean放到缓存中了
if (sharedInstance != null && args == null) {
//该方法是FactoryBean接口的调用入口
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
这回name = beanName,没有前缀了,所以接着getObjectForBeanInstance
往下运行
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.
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.
//如果实例不是FactoryBean类型的
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
//如果代码能走下来,则说明 beanName不是以&开头,并且beanInstance是FactoryBean类型的
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//从缓存里面拿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());
//这里就是拿到Student对象的方法,我们重点来看这里
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
重点我们来看这个方法getObjectFromFactoryBean
这个方法又调用了object = doGetObjectFromFactoryBean(factory, beanName);
doGetObjectFromFactoryBean
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//这个方法调用的就是工厂bean的getObject方法
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;
}
4. 小结
获取工厂对象本身要在工厂beanName
前加上&
标识,不加&
标识获取的就是工厂bean中的getObject
方法中返回的对象。
上一篇: 二叉树中和为值的路径
下一篇: 将一颗二叉树展开为链表
推荐阅读
-
replugin源码解析之replugin-host-gradle(宿主的gradle插件)
-
Spring5源码之AOP代理
-
Spring 核心思想 之反向控制概念解析(有例子) 博客分类: Spring iocspring反向控制
-
Spring 核心思想 之反向控制概念解析(有例子) 博客分类: Spring iocspring反向控制
-
Spring Cloud 2.2.2 源码之九Eureka服务端处理注册服务
-
Spring Boot 2.2.6 源码之旅三十五SpringMVC源码细节之拦截器
-
Spring Boot 2.2.6 源码之旅三十六SpringMVC源码细节之深入模型方法一
-
Spring Boot 2.2.6 源码之旅四十一SpringMVC源码细节之SimpleUrlHandlerMapping静态资源处理器一
-
Java阻塞队列之ArrayBlockingQueue源码解析
-
Java队列之ArrayBlockingQueue源码解析