天天看點

Spring注解啟動:AnnotationConfigApplicationContext原理

作者:搬山道猿
Spring注解啟動:AnnotationConfigApplicationContext原理

入口代碼:

public class SpringAnnotationStarter {
    public static void main(String[] args) {
        //建立一個新的AnnotationConfigApplicationContext,從給定的元件類派生bean定義并自動重新整理上下文。
        new AnnotationConfigApplicationContext(SpringAnnotationConfig.class);
    }
}

複制代碼           

在上面的測試中,使用的AnnotationConfigApplicationContext來重新整理上下文,傳入參數是我們定義的配置類。

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    register(componentClasses);
    refresh();
}
複制代碼           

點進去可以發現,首先是調用空參構造器,然後是注冊配置類,最後重新整理,是以從這三個步驟進行梳理

1. this()

這就是一個空參構造器。

public AnnotationConfigApplicationContext() {
   this.reader = new AnnotatedBeanDefinitionReader(this);
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}
複制代碼           

從代碼可以看出,是給reader和scanner兩個屬性進行指派。

reader的類型是AnnotatedBeanDefinitionReader ,點進去看源碼,這是個擴充卡,也就是adapter,用于bean類的程式設計注冊,解析帶有注解的bean的beanDefinition。在reader的指派如下:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
   this(registry, getOrCreateEnvironment(registry));
}
複制代碼           

傳入目前類,并且根據目前環境調用重載的構造進行上下文建立,getOrCreateEnvironment看名字大概就是沒有建立,有就擷取,這就不看了,直接去關注重載的構造器

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   Assert.notNull(environment, "Environment must not be null");
   this.registry = registry;
   this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
   AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
複制代碼           

這裡ConditionEvaluator點進去是為context指派,根據上下文建立一個ConditionContextImpl。

關鍵在于AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

AnnotationConfigUtils是一個Spring内部工具類,用于識别注解配置類中的bean定義,registerAnnotationConfigProcessors是為在給定的系統資料庫中注冊所有後置處理器,也就是PostProcessor。包括一些核心注解,形如:if(!registry.containsBeanDefinition(XXXXXXXXXXXXX))

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
                    BeanDefinitionRegistry registry, @Nullable Object source) {

   //從上下文拿到beanFactory
   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);
            //解析注解ConfigurationClassPostProcessor ,友善後續注冊BeanDefinition
   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));
   }
    //解析@Autowired ,友善後續注冊BeanDefinition
   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));
   }

   // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
   if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
       RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
       def.setSource(source);
       beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
   }

   // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
   if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
       RootBeanDefinition def = new RootBeanDefinition();
       try {
           def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                                               AnnotationConfigUtils.class.getClassLoader()));
       }
       catch (ClassNotFoundException ex) {
           throw new IllegalStateException(
               "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
       }
       def.setSource(source);
       beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
   }

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

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

   return beanDefs;
}
複制代碼           

最後将BeanDefinition集合傳回。到這裡reader就初始化完成了

然後scanner類型是為給定的bean工廠建立一個新的ClassPathBeanDefinitionScanner

一直往裡點可以得到:

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
                    Environment environment, @Nullable ResourceLoader resourceLoader) {

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

   if (useDefaultFilters) {
       registerDefaultFilters();//注冊@Component的預設Filters
   }
   setEnvironment(environment);//設定要在解析占位符和評估@Conditional注釋元件類時使用的環境。
   setResourceLoader(resourceLoader);//将ResourceLoader設定為用于資源位置。這通常是一個ResourcePatternResolver實作。
}
複制代碼           

從這裡可以得出,主要用于掃描注解的設定。

2. register(componentClasses);

在上一步中,通過reader和scanner分别對BeanFactory以及核心的注解,過濾器,環境等進行了配置。

register方法中,傳入的是我們寫的配置類。

跟進,發現調用的是reader的register方法。

@Override
public void register(Class<?>... componentClasses) {
   Assert.notEmpty(componentClasses, "At least one component class must be specified");
   this.reader.register(componentClasses);
}
複制代碼           

繼續跟進:

public void register(Class<?>... componentClasses) {
   for (Class<?> componentClass : componentClasses) {
       registerBean(componentClass);
   }
}
複制代碼           

周遊所有傳入的componentClasses,對Bean進行注冊,再跟進,我們會進入真正的注冊邏輯doRegisterBean

public void registerBean(Class<?> beanClass) {
   doRegisterBean(beanClass, null, null, null, null);
}
複制代碼           
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
                    @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
                    @Nullable BeanDefinitionCustomizer[] customizers) {

   //聲明BeanDefinition,下面都是填充屬性
   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
   if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
       return;
   }
    //設定用于建立bean執行個體的回調(可能為null)
   abd.setInstanceSupplier(supplier);
   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
   //作用域
   abd.setScope(scopeMetadata.getScopeName());
   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    //處理abd中的通用注解,@Lazy、@Primary、@DependsOn、@Role以及@Description
   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
   //下面這段關于qualifiers判斷是否有限定注解@Primary@Lazy
   if (qualifiers != null) {
       for (Class<? extends Annotation> qualifier : qualifiers) {
           if (Primary.class == qualifier) {
               abd.setPrimary(true);
           }
           else if (Lazy.class == qualifier) {
               abd.setLazyInit(true);
           }
           else {
               abd.addQualifier(new AutowireCandidateQualifier(qualifier));
           }
       }
   }
   //處理回調
   if (customizers != null) {
       for (BeanDefinitionCustomizer customizer : customizers) {
           customizer.customize(abd);
       }
   }
    //将abd封裝成BeanDefinitionHolder,然後對BeanDefinition注冊
   BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
   //代理
   definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
   //向BeanFactory進行注冊
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
複制代碼           

到這裡相當于把我們寫的配置注冊到Spring了。

3. refresh();

這個方法,點進去就是一個refresh方法,對應Spring的初始化中的refresh,org.springframework.context.support.AbstractApplicationContext#refresh,對應着Spring生命周期 下面這段是之前學Spring的時候在網上找的,大緻流程如下:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

        // 準備此上下文以進行重新整理、設定其啟動日期和活動标志以及執行任何屬性源的初始化。
        prepareRefresh();//重新整理前的預處理

        // 建立初始化BeanFactory,這個過程中loadBeanDefinitions()方法,輸入beanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);
         //  1.設定BeanFactory的類加載器為ApplicationContex的類加載器
		// 2.設定beanFacory的語言表達式處理器

        try {
            this.postProcessBeanFactory(beanFactory);
            // 執行BeanFactoryPostProcessor的方法,BeanFactory的後置處理器 
            // 在BeanFactory标準初始化之後執行的,調用各種BeanFactoryPostProcessor
            this.invokeBeanFactoryPostProcessors(beanFactory);
            // 注冊BeanPostProcessor(Bean的後置處理器),用于攔截bean建立過程
            this.registerBeanPostProcessors(beanFactory);
            // 初始化MessageSource元件(做國際化功能;消息綁定,消息解析).
            this.initMessageSource();
            // 初始化上下文的事件機制
            this.initApplicationEventMulticaster();
            // 可以用于子類實作在容器重新整理時自定義邏輯初始化
            this.onRefresh();
            // 注冊時間監聽器,将ApplicationListener注冊到容器中來
            this.registerListeners();
            // 初始化所有剩下的單執行個體bean,單例bean在初始化容器時建立。
            this.finishBeanFactoryInitialization(beanFactory);
            // 釋出完成事件,結束初始化過程
            this.finishRefresh();
        }

        catch (BeansException ex) {
            ...
            }
    }
}

複制代碼           

簡易流程圖

Spring注解啟動:AnnotationConfigApplicationContext原理