AnnotationConfigApplicationContext 源碼分析(一)

AnnotationConfigApplicationContext 源碼分析(一):新建對象

本文是作者的個人學(xué)習(xí)筆記,僅做參考,Spring代碼版本5.2.2

AnnotationConfigApplicationContext 作為繼承GenericApplicationContext的子類,歸屬于Spring容器。同時該類實現(xiàn)了AnnotationConfigRegistry注解,在GenericApplicationContext的基礎(chǔ)上為容器添加了一下兩個功能:

  1. 對攜帶spring注解的類的注冊。

  2. 掃描某個包下攜帶spring注解的類。

一、AnnotationConfigApplicationContext的基本使用

public class DemoApplication {
  public static void main(String[] args) {
    //1.新建AnnotationConfigApplicationContext對象
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    //2.注冊配置類
        applicationContext.register(MyConfiguration.class);
    //3.啟動容器
        applicationContext.refresh();
    //4.停止容器
    applicationContext.stop();
    //5.重啟容器
        applicationContext.start();
    //6.關(guān)閉容器
        applicationContext.close();
  }
}

在AnnotationConfigApplicationContext最基礎(chǔ)的使用中,我們啟動一個容器需要三個步驟,對應(yīng)上面的代碼

  1. 新建AnnotationConfigApplicationContext對象
  2. 注冊配置類
  3. 啟動容器

剩下的三個步驟一般不會使用,有時間也將會閱讀做分析

  1. 停止容器
  2. 重啟容器
  3. 關(guān)閉容器

二、新建AnnotationConfigApplicationContext對象

/**
 *  
 **/
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    private final AnnotatedBeanDefinitionReader reader;

    private final ClassPathBeanDefinitionScanner scanner;
  /**
     * Create a new AnnotationConfigApplicationContext that needs to be populated
     * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
     * 創(chuàng)建一個新的AnnotationConfigApplicationContext,它需要通過{@link#register}調(diào)用填充,
     * 然后手動{@linkplain#刷新}。
     *
     * 這里初始化了
     */
    public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);

        // Spring的掃描機(jī)制
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
  
  public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
    // 內(nèi)置一個DefaultListableBeanFactory對象
        super(beanFactory);
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
}

由上面我們可以看到新建一個AnnotationConfigApplicationContext對象的時候,將實例化兩個類,同時選擇性的內(nèi)置一個DefaultListableBeanFactory對象,以下將做具體的解析

1、 DefaultListableBeanFactory

這個類同GenericApplicationContext一樣,都實現(xiàn)了BeanFactory接口,作為容器使用,但是兩者沒有繼承關(guān)系。

GenericApplicationContext一般作為資源管理器使用,內(nèi)部對于bean的管理往往是通過內(nèi)置一個DefaultListableBeanFactory對象作為Bean管理器。

2、AnnotatedBeanDefinitionReader

/**
 * Convenient adapter for programmatic registration of bean classes.
 * <p>This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying
 * the same resolution of annotations but for explicitly registered classes only.
 
 * 便于bean類的編程注冊的適配器。
 * <p>這是{@link ClassPathBeanDefinitionScanner}的另一種選擇,它應(yīng)用相同的注釋解析,但僅適用于顯式注冊的類。
 */
public class AnnotatedBeanDefinitionReader {}

AnnotatedBeanDefinitionReader作為一個工具類,用于更方便的注冊bean,接下來我們看一下這個類的構(gòu)造函數(shù)

public class AnnotatedBeanDefinitionReader {
    private final BeanDefinitionRegistry registry;
    private ConditionEvaluator conditionEvaluator;

    /**
     * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
     * using the given {@link Environment}.
     * @param registry the {@code BeanFactory} to load bean definitions into,
     * in the form of a {@code BeanDefinitionRegistry}
     * @param environment the {@code Environment} to use when evaluating bean definition
     * profiles.
     *
     * 使用給定的{@link Environment},為給定的注冊表創(chuàng)建一個新的{@code AnnotatedBeanDefinitionReader}。
     * @param registry 以{@code BeanDefinitionRegistry}的形式將bean定義加載到{@code BeanFactory}
     * @param environment 在計算bean定義概要文件時要使用的{@code Environment}。
     * @since 3.1
     */
    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
        this.registry = registry;
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
  }
}

由上面代碼可以看到,AnnotatedBeanDefinitionReader實例化需要的兩個參數(shù)

  1. BeanDefinitionRegistry:bean定義的注冊器,由GenericApplicationContext實現(xiàn),AnnotationConfigApplicationContext繼承。
  2. Environment:環(huán)境變量,這里先不討論,后面補(bǔ)充

AnnotatedBeanDefinitionReader實例化的邏輯

  1. 持有一個BeanDefinitionRegistry/bean定義的注冊器
  2. 通過registry,environment參數(shù)創(chuàng)建一個ConditionEvaluator對象,ConditionEvaluator對象的作用是用于解析注解@Conditional,這里先不做過多關(guān)注
  3. 通過工具類AnnotationConfigUtils,注冊AnnotationConfigProcessors

接下來我們一次看一下ConditionEvaluator對象的創(chuàng)建和解析AnnotationConfigProcessors的注冊

ConditionEvaluator對象的創(chuàng)建

/**
 * Internal class used to evaluate {@link Conditional} annotations.
 * 用于計算{@link Conditional}批注的內(nèi)部類。
 *
 */
class ConditionEvaluator {
    private final ConditionContextImpl context;
  
    /**
     * Create a new {@link ConditionEvaluator} instance.
     * 用于計算{@link Conditional}批注的內(nèi)部類。
     */
    public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry,
            @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
        this.context = new ConditionContextImpl(registry, environment, resourceLoader);
    }
}

注冊AnnotationConfigProcessors


public abstract class AnnotationConfigUtils {
  /**
     * Register all relevant annotation post processors in the given registry.
     * @param registry the registry to operate on
     * @param source the configuration source element (already extracted)
     * that this registration was triggered from. May be {@code null}.
     * @return a Set of BeanDefinitionHolders, containing all bean definitions
     * that have actually been registered by this call
     * 
     * 注冊在給定的注冊表中所有相關(guān)的批注后置處理器。
     * @param source 觸發(fā)此注冊的配置源元素(已提取)??赡苁莧@code null}。
     * @return 一組BeanDefinitionHolders,包含此調(diào)用實際注冊的所有bean定義
     */
  public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {
        //步驟一
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }
        //步驟二
        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        。。。

        return beanDefs;
    }
}

上面代碼將分成幾部分步驟:

  1. 獲取DefaultListableBeanFactory對象,
    1. 需要注意的是,;
    2. 如果beanFactory(DefaultListableBeanFactory不為空),將為該對象設(shè)置兩個對象,這里不做討論:
      1. AnnotationAwareOrderComparator
      2. ContextAnnotationAutowireCandidateResolver
  2. 為當(dāng)前容器registry注冊多個BeanFactory后置處理器
    1. 注冊的過程
      1. 利用后置處理器類對象和source對象(配置)生成一個BeanDefinition(Bean定義)對象;
      2. 用指定的bean名稱和BeanDefinition對象,一起注冊到registry中,并返回一個BeanDefinitionHolder對象(該對象持有BeanDefinition對象,bean的名稱,bean的別名列表)
      3. 將BeanDefinitionHolder添加到指定列表中,作為最后的結(jié)果返回,這里并無利用到結(jié)果。
    2. BeanFactory后置處理器將干預(yù)Spring在注冊,掃描,解析,生成BeanDefinition等的整個過程,后面將會具體解析。
    3. Spring支持用戶注冊自定義的BeanFactory后置處理器,同時,Spring在不同的容器中也注冊實現(xiàn)不同功能的后置處理器,以下是在當(dāng)前方法中注冊的跟注解相關(guān)的后置處理器的簡單介紹,在后面調(diào)用中將做具體解析
      1. CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME:
        1. 作用:內(nèi)部托管配置注釋處理器。
        2. 對應(yīng)的類:ConfigurationClassPostProcessor.class
      2. AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME
        1. 作用:內(nèi)部管理的自動注入注解處理器
        2. 對應(yīng)的類:AutowiredAnnotationBeanPostProcessor.class
      3. COMMON_ANNOTATION_PROCESSOR_BEAN_NAME
        1. 作用:內(nèi)部管理的JSR-250注釋處理器
        2. 對應(yīng)的類:CommonAnnotationBeanPostProcessor.class
      4. PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME
        1. 作用:內(nèi)部管理的JPA注釋處理器(不一定注入)。
        2. 對應(yīng)的類:PersistenceAnnotationBeanPostProcessor.class
      5. EVENT_LISTENER_PROCESSOR_BEAN_NAME
        1. 作用:內(nèi)部管理的@EventListener注釋處理器
        2. 對應(yīng)的類:EventListenerMethodProcessor.class
      6. EVENT_LISTENER_FACTORY_BEAN_NAME
        1. 作用:內(nèi)部管理的EventListenerFactory。
        2. 對應(yīng)的類:DefaultEventListenerFactory.class

3、ClassPathBeanDefinitionScanner

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
  /**
     * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
     * using the given {@link Environment} when evaluating bean definition profile metadata.
     * @param registry the {@code BeanFactory} to load bean definitions into, in the form
     * of a {@code BeanDefinitionRegistry}
     * @param useDefaultFilters whether to include the default filters for the
     * {@link org.springframework.stereotype.Component @Component},
     * {@link org.springframework.stereotype.Repository @Repository},
     * {@link org.springframework.stereotype.Service @Service}, and
     * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
     * @param environment the Spring {@link Environment} to use when evaluating bean
     * definition profile metadata
     * @param resourceLoader the {@link ResourceLoader} to use
     *
     * 為給定的bean工廠創(chuàng)建一個新的{@code ClassPathBeanDefinitionScanner},
     * 并在計算bean定義概要文件元數(shù)據(jù)時使用給定的{@link Environment}。
     * @param registry 以{@code BeanDefinitionRegistry}的形式將bean定義加載到{@code BeanFactory}
     * @param useDefaultFilters 是否包含
     * {@link org.springframework.stereotype.Component@Component}、
     * {@link org.springframework.stereotype.Repository@Repository}、
     * {@link org.springframework.stereotype.Service@Service}和
     * {@link org.springframework.stereotype.Controller@Controller}構(gòu)造型批注的默認(rèn)篩選器
     * @param environment 在計算bean定義概要文件元數(shù)據(jù)時使用的Spring{@link Environment}
     * @param resourceLoader 要使用的{@link ResourceLoader}
     *
     * @since 4.3.6
     */
    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
            Environment environment, @Nullable ResourceLoader resourceLoader) {

        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;

        //關(guān)鍵代碼,Spring 內(nèi)部默認(rèn)為true
        //使用默認(rèn)的Filters
        if (useDefaultFilters) {
            registerDefaultFilters();
        }
        setEnvironment(environment);
        setResourceLoader(resourceLoader);
    }
}

ClassPathBeanDefinitionScanner故名思義,是專門用于掃描類并將符合條件的類注冊為BeanDefinition的工具對象。

ClassPathBeanDefinitionScanner構(gòu)造函數(shù)的三個參數(shù):

  1. registry(BeanDefinitionRegistry):
  2. useDefaultFilters(boolean):用于判斷是否使用默認(rèn)的注解過濾器(AnnotationTypeFilter)
    1. 注解過濾器/AnnotationTypeFilter:用于處理特定注解,有黑名單和白名單,先執(zhí)行黑名單
      1. 黑名單/excludeFilters:標(biāo)記該注解的類將不會被解析成Bean,即使在白名單中存在
      2. 白名單/includeFilters:標(biāo)記該注解的類將會被解析成Bean
  3. environment(Environment):
  4. resourceLoader(ResourceLoader):資源加載器,這里先不做描述
    1. 這里資源加載器指的是AnnotationConfigApplicationContext對象
    2. 繼承實現(xiàn)鏈為
      • AnnotationConfigApplicationContext—>
      • DefaultResourceLoader—>
      • GenericApplicationContext—>
      • AbstractApplicationContext—>
      • DefaultResourceLoader—>
      • ResourceLoader

構(gòu)造函數(shù)初始化的過程:

1. 持有一個BeanDefinitionRegistry/bean對象(定義的注冊器)
2. 判斷是否使用默認(rèn)的注解過濾器AnnotationTypeFilter.class,默認(rèn)為是,如果是將注冊以下注解
    1. 白名單:@Component,@ManagedBean,@Named
    2. 黑名單:無
3. 持有Environment對象
4. 通過resourceLoader對象生成對應(yīng)的對象被ClassPathBeanDefinitionScanner持有,暫時不解析以下類
    1. resourcePatternResolver(ResourcePatternResolver):新建PathMatchingResourcePatternResolver對象
    2. metadataReaderFactory(MetadataReaderFactory):新建CachingMetadataReaderFactory對象
    3. componentsIndex(CandidateComponentsIndex):利用resourceLoader的類加載器新建CandidateComponentsIndex對象

總結(jié)

在實例化AnnotationConfigApplicationContext對象的時候,做了三件事情:

  1. 新建一個AnnotatedBeanDefinitionReader對象用于注冊一個類到容器中,而一般我們注冊的類通常是配置類;
  2. 同時注冊幾個BeanFactory后置處理器到容器中;
  3. 新建一個ClassPathBeanDefinitionScanner對象用于掃描和注冊類中。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容