Spring Framework 源碼閱讀(三):認識FactoryBean
FactoryBean
和
BeanFactory
雖然從命名上看起來相似,但作用卻大不相同,
BeanFactory
負責建立和管理
Spring
容器中的
bean
,為
bean
從初始化到銷毀建立了一整套統一的流程,讓使用者可以不需要關注複雜的流程,隻需關注
bean
本身的邏輯。而
FactoryBean
可以提供自定義
bean
初始化流程的功能,是以
FactoryBean
可以用于建立一類
bean
。
FactoryBean
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
- 如果一個
實作了bean
接口,那麼該FactoryBean
将作為某一類bean
的工廠,而不是直接作為一個bean
。bean
- 實作
接口的FactoryBean
不能用作普通bean
。bean
是以FactoryBean
定義的,但是bean
引用的對象始終是bean
方法建立的對象。getObject
-
(不是單指FactoryBean
接口)可以支援單例和原型,并且可以根據需要以懶加載的形式建立對象,也可以在啟動時立即建立對象。FactoryBean
接口允許更細粒度的行為中繼資料。SmartFactoryBean
-
接口在FactoryBean
架構中大量使用,例如Spring
或ProxyFactoryBean(AOP)
。它也可用于定制JndiObjectFactoryBean
。component
SmartFactoryBean
接口源碼:
public interface SmartFactoryBean<T> extends FactoryBean<T> {
default boolean isPrototype() {
return false;
}
default boolean isEagerInit() {
return false;
}
}
建立module
先在
Spring Framework
源碼中增加一個
application module
,這在之前的博文中已經介紹過了,這裡就不再贅述:
- Spring Framework 源碼閱讀(一):Aware接口及其實作類的作用
IMessageService
接口:
package com.kaven.service;
/**
* @Author: ITKaven
* @Date: 2021/09/25 14:04
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/
public interface IMessageService {
default String getMessage() {
return "default message";
}
}
MessageServiceImpl
實作類:
package com.kaven.service.impl;
import com.kaven.service.IMessageService;
/**
* @Author: ITKaven
* @Date: 2021/09/25 14:05
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/
public class MessageServiceImpl implements IMessageService {
public String message;
public MessageServiceImpl(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
}
MessageServiceFactoryBean
類(實作
FactoryBean
接口):
package com.kaven.factory;
import com.kaven.service.IMessageService;
import com.kaven.service.impl.MessageServiceImpl;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
/**
* @Author: ITKaven
* @Date: 2021/10/28 20:01
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/
@Component("myFactoryBean")
public class MessageServiceFactoryBean implements FactoryBean<IMessageService> {
@Override
public IMessageService getObject() throws Exception {
return new MessageServiceImpl("Hello Spring");
}
@Override
public Class<?> getObjectType() {
return IMessageService.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
Application
啟動類:
package com.kaven;
import com.kaven.factory.MessageServiceFactoryBean;
import com.kaven.service.IMessageService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import java.util.Arrays;
/**
* @Author: ITKaven
* @Date: 2021/09/25 13:54
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/
@ComponentScan({"com.kaven"})
public class Application {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Application.class);
IMessageService messageServiceBean = (IMessageService) applicationContext.getBean("myFactoryBean");
System.out.println(messageServiceBean.getMessage());
IMessageService messageServiceBean2 = (IMessageService) applicationContext.getBean("myFactoryBean");
System.out.println("messageServiceBean == messageServiceBean2: " + (messageServiceBean == messageServiceBean2));
MessageServiceFactoryBean messageServiceFactoryBean = (MessageServiceFactoryBean) applicationContext.getBean("&myFactoryBean");
System.out.println("isSingleton: " + messageServiceFactoryBean.isSingleton());
System.out.println(applicationContext.getBeanDefinitionCount());
Arrays.stream(applicationContext.getBeanDefinitionNames()).forEach(System.out::println);
}
}
運作輸出:
> Task :application:Application.main()
Hello Spring
messageServiceBean == messageServiceBean2: false
isSingleton: false
6
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
application
myFactoryBean
很顯然輸出結果符合預期,通過
FactoryBean
的
bean
名稱擷取
bean
,隻會擷取該
FactoryBean
中
getObject()
方法傳回的執行個體,也就是這裡的
MessageServiceImpl
執行個體,如果想要擷取
FactoryBean
本身的
bean
,需要在
FactoryBean
的
bean
名稱前拼接一個
&
字元,在代碼中已經有示範了。
想要了解為什麼會建立下面這
4
個
bean
,可以閱讀這篇部落格:
- Spring Framework 源碼閱讀(二):BeanDefinition的作用
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
源碼分析
現在開始分析為什麼實作了
FactoryBean
接口,就可以自定義建立某一類
bean
的流程了,以及擷取
FactoryBean
本身的
bean
,為什麼要在
FactoryBean
的
bean
名稱前拼接一個
&
字元。
自定義的
bean
,大部分會在
DefaultListableBeanFactory
類的
preInstantiateSingletons
方法中被開始建立(删除了部分代碼):
@Override
public void preInstantiateSingletons() throws BeansException {
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
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);
}
}
}
}
Debug
如下圖所示:
關注這一行(
!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()
結果是
true
,這些在
AbstractBeanDefinition
抽象類中設定了預設值,部落客在上一篇部落格中進行了介紹,并且
isFactoryBean
方法也會傳回
true
,因為它就是
FactoryBean
):
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
String FACTORY_BEAN_PREFIX = "&";
很顯然
beanName
就是
FactoryBean
的
bean
名稱,而
FACTORY_BEAN_PREFIX + beanName
就是
&myFactoryBean
,是以這裡是擷取
FactoryBean
本身的
bean
。
後面還會調用
AbstractBeanFactory
抽象類的
getObjectForBeanInstance
方法(删除了部分代碼):
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
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;
}
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
getObjectForBeanInstance
方法會進行判斷選擇分支,會有三個分支,如果是擷取
FactoryBean
本身的
bean
(
getObjectForBeanInstance
方法中的
beanInstance
參數其實在前面的調用鍊中已經被建立,如上圖所示的
sharedInstance
變量,這裡就不詳細介紹,不然顯得太雜亂,部落客會在以後的部落格中詳細介紹
bean
的建立流程和生命周期),就會進入第一個分支:
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;
}
BeanFactoryUtils
抽象類的
isFactoryDereference
方法(就是判斷
name
參數在不為
null
的情況下有沒有
&
字首):
public static boolean isFactoryDereference(@Nullable String name) {
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
是以第一個分支就是傳回
FactoryBean
本身的
bean
。
第二個分支(
beanInstance
參數不是
FactoryBean
執行個體,就是傳回跟
factory
不相關的
bean
):
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
第三個分支(很顯然是傳回
FactoryBean
對應的那一類
bean
,下面會詳細介紹):
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
回到擷取
FactoryBean
本身
bean
的
preInstantiateSingletons
方法中的這個部分:
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);
}
}
SmartFactoryBean
接口的源碼在上面已經展示過了,非常簡單,就是繼承了
FactoryBean
接口,并且增加了兩個方法,比如上面出現的
isEagerInit()
方法,這些源碼都是互相聯系的,大家還是要親自
Debug
體驗一下。是以這裡的
isEagerInit
變量是
false
,因為
MessageServiceFactoryBean
類實作的是
FactoryBean
接口,是以實作
FactoryBean
接口的
MessageServiceFactoryBean
類不會立即(懶加載)建立它對應的那一類
bean
(
MessageServiceImpl
執行個體)。如果實作
SmartFactoryBean
接口,并且讓
isEagerInit
方法傳回
true
,在建立
FactoryBean
本身的
bean
後,也會立即建立
FactoryBean
對應的那一類
bean
,大家可以動手試一試。
是以,在
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Application.class);
這行代碼結束後,
FactoryBean
本身的
bean
就已經在
Spring
容器中了,以便後續可以建立該
FactoryBean
對應的那一類
bean
。
之後通過
FactoryBean
的
bean
名稱來擷取
bean
,就是該
FactoryBean
對應的那一類
bean
(通過
getObject
方法傳回的執行個體)。
IMessageService messageServiceBean = (IMessageService) applicationContext.getBean("myFactoryBean");
Bebug
如下圖所示:
會調用
AbstractBeanFactory
抽象類的
getObjectForBeanInstance
方法(删除了部分代碼),并且
factory
參數就是之前建立好的
FactoryBean
本身的
bean
(上面說過這裡的
beanInstance
參數就是
FactoryBean
本身的
bean
,并且已經在之前的調用鍊中被建立好了,這裡隻是強轉為
FactoryBean<?>
類型,友善後續調用
getObject
方法)。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
重點在這一行:
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
調用了
FactoryBeanRegistrySupport
抽象類的
getObjectFromFactoryBean
方法(删除了部分代碼):
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) {
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
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);
}
}
}
return object;
}
}
else {
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);
}
}
return object;
}
}
這裡的
factory.isSingleton()
會傳回
false
,是以會執行下面這一行:
Object object = doGetObjectFromFactoryBean(factory, beanName);
調用了
FactoryBeanRegistrySupport
抽象類的
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 {
object = factory.getObject();
}
}
return object;
}
最終會執行
object = factory.getObject();
,而
factory
參數就是之前建立好的
FactoryBean
本身的
bean
,是以會調用
FactoryBean
中的
getObject
方法,建立了與該
FactoryBean
對應的那一類
bean
。
Debug
如下圖所示: