天天看點

Spring Framework 源碼閱讀(三):認識FactoryBean

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接口及其實作類的作用​​
Spring Framework 源碼閱讀(三):認識FactoryBean

​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​

​如下圖所示:

Spring Framework 源碼閱讀(三):認識FactoryBean

關注這一行(​

​!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;
  }      
Spring Framework 源碼閱讀(三):認識FactoryBean

​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​

​如下圖所示:

Spring Framework 源碼閱讀(三):認識FactoryBean

會調用​

​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​

​如下圖所示:

Spring Framework 源碼閱讀(三):認識FactoryBean