1. FactoryBean
FactoryBean
It is Spring
one of the core interfaces provided by the framework to create objects that are complex or cannot be created through the default constructor. In this case, by implementing FactoryBean
the interface, you can customize the instantiation Bean
process, including Bean
the object type, initialization, destruction, etc.
In application scenarios, you can use to FactoryBean
integrate third-party frameworks, open source libraries, or handle some special business needs, and let Bean
us flexibly control the control.
For example: by FactoryBean
encapsulating the logic of object creation, the user is not aware of it, and can IOC
be obtained from the container normally Bean
.
If you want to get FactoryBean
itself, you can beanName
add a &
symbol in front of , which we will experience later in the source code analysis.
Here are FactoryBean
the components of :
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
Corresponding to the description of the three core methods:
isSingleton()
: Gets whether the instanceFactoryBean
created byBean
is a singleton or a prototype, the default is a singleton.T getObject()
: Get the instanceFactoryBean
created byBean
, ifisSingleton
the scope is singleton, the instance will be cached.Class<?> getObjectType()
: Get the typeFactoryBean
to be created byBean
.
The following is a simple experience FactoryBean
of using:
@Component
public class FactoryBeanTest implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new TestABC();
}
@Override
public Class<?> getObjectType() {
return TestABC.class;
}
@Override
public boolean isSingleton() {
return true;
}
/**
* 实际Bean
*/
public static class TestABC{
}
}
test:
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("com.example.demo.bean");
System.out.println(context.getBean("factoryBeanTest"));
System.out.println(context.getBean("&factoryBeanTest"));
}
}
It can be seen that if it &
starts with the symbol, what is obtained is FactoryBean
itself.
Let's analyze from the perspective of source code, how to deal with in the process of context.getBean
obtaining .Bean
FactoryBean
Two, source code interpretation
In the previous article of this column Bean
, the source code analysis of the creation process was carried out. If you understand it, you should know that the actual Bean
creation logic is in AbstractBeanFactory
the doGetBean
method. Here is also doGetBean
the method. If Bean
you don’t know the creation process, you can also refer to the following article:
Spring source code analysis - Bean creation process and resolution of circular dependencies
In doGetBean
the method, it will first go to the singleton pool to find out whether it exists, and if it exists, it will use getObjectForBeanInstance
to get the final Bean
instance:
If there is none in the singleton pool at this time, perform the following Bean
instance initialization process, and also use to getObjectForBeanInstance
obtain the final Bean
instance after the instantiation is completed
This method may seem inconspicuous, but it actually FactoryBean
plays a key role in the method. Let's mainly look at getObjectForBeanInstance
the method below:
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.
// 当前bean的名称是否是工厂模式, 主要判断名称是否以 & 开头,如果是以 & 开头,说明当前获取的是 FactoryBean 本身
if (BeanFactoryUtils.isFactoryDereference(name)) {
// 如果是 NullBean 直接返回
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 如果不是 FactoryBean 的话则抛出异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
// 返回 FactoryBean 自身
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实例不是 FactoryBean,则直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
// 是 FactoryBean 的情况下
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 从缓存中获取
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 转为 FactoryBean 类型
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 实际的 Bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
In this method, the first step is to name
judge . If it &
starts with , it means that the current acquisition is FactoryBean
itself. If it Bean
is neither NullBean
nor , FactoryBean
only an error is reported.
If it is not of the type below FactoryBean
, just return the current instance directly.
The following logic must be FactoryBean
of the type. If it does not exist in the cache, the method is finally called getObjectFromFactoryBean
to obtain it Bean
. The following shows the method:
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 如果 FactoryBean 里的 Bean 是单例模型, 并且单例池中存在
if (factory.isSingleton() && containsSingleton(beanName)) {
// 对单例池加锁
synchronized (getSingletonMutex()) {
//尝试从缓冲中获取Bean
Object object = this.factoryBeanObjectCache.get(beanName);
// 如果缓存中不存在
if (object == null) {
// 从 FactoryBean 中的 getObject() 获取 Bean
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
// 再次尝试获取缓存
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
// 如果缓存存在使用缓存中的Bean
object = alreadyThere;
} else {
// 缓存中依然不存在,是否需要触发后通知
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
} finally {
afterSingletonCreation(beanName);
}
}
// 加入缓存
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
// 返回实际的 Bean
return object;
}
} else {
// 如果不是单例模式 或 单例池中不存在
// 从 FactoryBean 中获取 Bean
Object object = doGetObjectFromFactoryBean(factory, beanName);
// 是否需要触发后通知
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
// 返回实际的 Bean
return object;
}
}
There are two branches here, whether FactoryBean
the Bean
is a singleton or not, that is, isSingleton
the method is true
or false
, if it is a singleton, try to factoryBeanObjectCache
get the cache object through , from here we can see that the singleton cache of in exists FactoryBean
in , not the singleton pool of .Bean
factoryBeanObjectCache
Spring
In this method, the actual acquisition Bean
is through doGetObjectFromFactoryBean
the method. If it is a singleton mode, Bean
put it factoryBeanObjectCache
into the cache. If it is not a singleton, it will directly return the obtained one Bean
. See doGetObjectFromFactoryBean
the method below:
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 {
// 调用 FactoryBean 中的 getObject 获取实际 Bean。
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;
}
It is more intuitive here, and the final instance is obtained by calling the method FactoryBean
of .getObject
Bean