Spring源碼閱讀之初始化"非懶加載bean"實例-第2篇

上一篇我們分析了創建bean實例需要的RootBeanDefinition定義的構建。今天我們在接着繼續討論,拿到RootBeanDefinition定義後,如何創建bean實例。但在創建bean實例前還有個很重要的知識點需要提前講解一下什麼是FactoryBean,因爲在創建bean實例的時候很多地方會遇到。

目前Spring創建bean實例都是通過配置指定的class屬性,利用反射的方式來創建的,但是在某些情況下,通過配置的方式創建bean實例並不靈活,所以Spring提供了另外一種方式來創建bean實例,就是通過實現FactoryBean接口,重寫其方法,通過調用getObject()方法來獲取bean實例,Spring本身也大量使用這種方式來創建bean實例。接下來我們來具體看下如果使用FactoryBean創建一個bean實例出來。

  1. 實現FactoryBean接口,重寫其方法,源碼如下。

package Service;

import org.springframework.beans.factory.FactoryBean;

import model.Car;

/**
 * @author zxz
 * 實現FactoryBean接口,重寫其方法
 */
public class CarFactoryBean implements FactoryBean<Car> {
    /**
     * 返回實際的bean實例,該方法會在getBean的時候通過CarFactoryBean對象調用
     *
     * @return
     * @throws Exception
     */
    public Car getObject() throws Exception {
        return new Car("audi", 300000);
    }

    /**
     * 返回實際的bean對應的class類型
     *
     * @return
     */
    public Class<?> getObjectType() {
        return Car.class;
    }

    /**
     * 返回bean實例是否是單例,true:表示目標實例是單例的,會被保存在BeanFactory裏面,false:表示目標實例非單例,每次都會創建一個新的目標bean實例出來。
     *
     * @return
     */
    public boolean isSingleton() {
        return true;
    }
}
package model;

/**
 * @author zxz
 * 目標實例
 */
public class Car {
    private String brand;
    private int price;

    public Car(String brand, int price) {
        this.brand = brand;
        this.price = price;
}

  1. CarFactoryBean通過配置的方式注入到BeanFactory裏面,具體配置如下。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="car" class="Service.CarFactoryBean"/>
</beans>

  1. 測試用例。

import model.Car;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author zxz
 */
public class JuniteTest {

    @Test
    public void testBeanPostProcessor() {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        Car car = (Car) context.getBean("car");
        System.out.println("brand: " + car.getBrand() + " , price: " + car.getPrice());
    }
}

  1. 測試用例比較簡單,我們來看下Car實例創建原理是什麼樣子的吧?回到上一篇文章的preInstantiateSingletons()方法。接着看創建完RootBeanDefinition定義之後的邏輯。

public void preInstantiateSingletons() throws BeansException {
      if (this.logger.isDebugEnabled()) {
          this.logger.debug("Pre-instantiating singletons in " + this);
      }

      // Iterate over a copy to allow for init methods which in turn register new bean definitions.
      // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
      List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

      // Trigger initialization of all non-lazy singleton beans...
      for (String beanName : beanNames) {
          RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
          if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
              // 就是這裏,判斷當前的beanName對應的bean是否是一個FactoryBean。
              if (isFactoryBean(beanName)) {
                  // 如果是一個FactoryBean,則獲取對應的FactoryBean實例。
                  Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                  if (bean instanceof FactoryBean) {
                      final 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);
              }
          }
      }

      // Trigger post-initialization callback for all applicable beans...
      for (String beanName : beanNames) {
          Object singletonInstance = getSingleton(beanName);
          if (singletonInstance instanceof SmartInitializingSingleton) {
              final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
              if (System.getSecurityManager() != null) {
                  AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                      smartSingleton.afterSingletonsInstantiated();
                      return null;
                  }, getAccessControlContext());
              }
              else {
                  smartSingleton.afterSingletonsInstantiated();
              }
          }
      }
}

  1. 來看看isFactoryBean()是怎麼根據beanName判斷是否是一個FactoryBean

public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
      // Step1:解析名字,之前的文章分析過,忘記的朋友翻翻原來的文章。
      String beanName = transformedBeanName(name);
      // Step2:根據beanName從緩存中獲取對應的bean實例。這個時候緩存裏面肯定沒有,所以這裏返回空。
      Object beanInstance = getSingleton(beanName, false);
      if (beanInstance != null) {
          // Step3:如果緩存能取到則直接返回。
          return (beanInstance instanceof FactoryBean);
      }

      // No singleton instance found -> check bean definition.
      // Step4:如果當前BeanFactory不存在對應的BeanDefinition定義 && 獲取父BeanFactory並且如果實現了ConfigurableBeanFactory,則從父BeanFactory判斷beanName是否是一個FactoryBean。
      if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
          // No bean definition found in this factory -> delegate to parent.
          return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
      }
      // Step5:根據beanName和RootBeanDefinition判斷是否是FactoryBean。
      return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
      // Step1:獲取beanName對應的Class類型
      Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
      // Step2:class類型不爲null && class類型是通過FactoryBean分配的。則認爲是一個FactoryBean,isAssignableFrom()是一個native方法。
      return (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
}

  1. 接着來看下beanName對應的Class類型是如何獲取到的,此處調用的AbstractAutowireCapableBeanFactory.predictBeanType()方法。

protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
      // Step1:根據beanName和mbd確定目標類型
      Class<?> targetType = determineTargetType(beanName, mbd, typesToMatch);

      // Apply SmartInstantiationAwareBeanPostProcessors to predict the
      // eventual type after a before-instantiation shortcut.
      // Step2:如果獲取到了對應的class類型 && mbd是合成的 && 存在InstantiationAwareBeanPostProcessors(我們這裏沒有,所以if條件不成立)
      if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
          // Step2.1:遍歷所有的BeanPostProcessor來獲取對應的class類型
          for (BeanPostProcessor bp : getBeanPostProcessors()) {
              if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                  SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                  Class<?> predicted = ibp.predictBeanType(targetType, beanName);
                  if (predicted != null && (typesToMatch.length != 1 || FactoryBean.class != typesToMatch[0] ||
                          FactoryBean.class.isAssignableFrom(predicted))) {
                      return predicted;
                  }
              }
          }
      }
      // Step3:返回獲取到的class類型
      return targetType;
}

  1. 來看看class類型是怎麼被確定下來的。

protected Class<?> determineTargetType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
      // Step1:通過mbd(RootBeanDefinition定義)獲取class類型。
      Class<?> targetType = mbd.getTargetType();
      if (targetType == null) {
          // Step2:通過mbd指定的factory獲取對應的class類型,如果沒有指定Factory,則通過resolveBeanClass獲取class類型。
          targetType = (mbd.getFactoryMethodName() != null ?
                  getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
                  resolveBeanClass(mbd, beanName, typesToMatch));
          if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) {
              mbd.resolvedTargetType = targetType;
          }
      }
      // Step3:返回class類型。
      return targetType;
}

  1. 接着來看看如何從resolveBeanClass()中獲取到class類型。

protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
			throws CannotLoadBeanClassException {
      try {
          // Step1:mbd如果指定了class類型,則直接返回該class類型。
          if (mbd.hasBeanClass()) {
              return mbd.getBeanClass();
          }
          // Step2:如果有安全檢查,優先優先做安全檢查,然後通過doResolveBeanClass獲取到class類型並返回。
          if (System.getSecurityManager() != null) {
              return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
                  doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
          }
          else {
              return doResolveBeanClass(mbd, typesToMatch);
          }
      }
      catch (PrivilegedActionException pae) {
          ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
          throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
      }
      catch (ClassNotFoundException ex) {
          throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
      }
      catch (LinkageError err) {
          throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
      }
}

  1. 接着看看doResolveBeanClass()的真正實現,FactoryBean對應的class類型也是從這裏確定的。

private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
			throws ClassNotFoundException {
      // Step1:獲取ClassLoader
      ClassLoader beanClassLoader = getBeanClassLoader();
      ClassLoader classLoaderToUse = beanClassLoader;
      // Step2:如果指定了要獲取class類型,則獲取對應的模板classLoader,我們這沒有,可以忽略該方法。
      if (!ObjectUtils.isEmpty(typesToMatch)) {
          // When just doing type checks (i.e. not creating an actual instance yet),
          // use the specified temporary class loader (e.g. in a weaving scenario).
          ClassLoader tempClassLoader = getTempClassLoader();
          if (tempClassLoader != null) {
              classLoaderToUse = tempClassLoader;
              if (tempClassLoader instanceof DecoratingClassLoader) {
                  DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
                  for (Class<?> typeToMatch : typesToMatch) {
                      dcl.excludeClass(typeToMatch.getName());
                  }
              }
          }
      }
      // Step3:獲取RootBeanDefinition定義的class名字
      String className = mbd.getBeanClassName();
      if (className != null) {
          // Step3.1:根據類名和mbd計算一個結果用來比較,由於我們測試用例指定的比較簡單,所以這裏返回的名字肯定和className相同。這個方法執行了一些表達式計算,具體內容可自行了解。
          Object evaluated = evaluateBeanDefinitionString(className, mbd);
          if (!className.equals(evaluated)) {
              // A dynamically resolved expression, supported as of 4.2...
              if (evaluated instanceof Class) {
                  return (Class<?>) evaluated;
              }
              else if (evaluated instanceof String) {
                  return ClassUtils.forName((String) evaluated, classLoaderToUse);
              }
              else {
                  throw new IllegalStateException("Invalid class name expression result: " + evaluated);
              }
          }
          // When resolving against a temporary class loader, exit early in order
          // to avoid storing the resolved Class in the bean definition.
          if (classLoaderToUse != beanClassLoader) {
              return ClassUtils.forName(className, classLoaderToUse);
          }
      }
      // Step4:利用Class.forName返回一個Class類型。
      return mbd.resolveBeanClass(beanClassLoader);
}

總結

到此我們就獲取到了beanName對應的class類型,從而判斷其是否是一個FactoryBean。有些朋友看到這裏應該會比較迷惑BeanFactoryFactoryBean,這裏簡單給大家解釋一下。

  • BeanFactory:是一個Bean工廠,是一個IoC容易,用於存放Bean實例的。

  • FactoryBean:它本身是一種特殊的bean,通過FactoryBean可以創建出指定的bean實例,即調用其getObject()獲得。所以也就是BeanFactory是用來管理FactoryBean的。

注意

  1. 在xml文件中我們指定的是FactoryBean,而非目標Bean

  2. 通過context.getBean("car")方式獲取到的bean實例是目標bean,如果我們想要的是FactoryBean本身,而非目標bean實例,則通過context.getBean("&car")就可以獲得。

  3. FactoryBeangetObject()方法是在第一次getBean的時候纔會被調用,如果isSingleton()方法返回true,則下次使用時直接從BeanFactory裏面獲取。

講清楚了這個概念之後,下篇文章我們來接着看bean實例的創建過程,敬請期待。

歡迎關注我,共同學習

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章