Spring Boot源碼分析——自動裝配

IZONE采源呀(?′ω`?)

Spring IOC容器可以自動裝配(autowire)相互協(xié)作bean之間的關(guān)聯(lián)關(guān)系,簡單來說,Spring的自動裝配可以幫助我們處理bean與bean之間的關(guān)系,不用我們?nèi)ヅ渲盟麄冊撌褂媚膫€類。這樣帶來的好處是能明顯減少配置的工作量(用bean模板其實也可以實現(xiàn)同樣的效果),并且能使配置與代碼同步更新。但其壞處就是會導致裝配不明確,降低配置文件的可讀性。

Spring自動裝配有5種方式:

  • no:默認不使用
  • byName:根據(jù)屬性名
  • byType:根據(jù)屬性類型
  • constructor:根據(jù)構(gòu)造器參數(shù)
  • autodetect:根據(jù)bean類的自省機制(introspection)來決定是用constructor還是byType

眾所周知,所有Spring Boot項目的啟動入口都是@SpringBootApplication,同時本文分析的“自動裝配”也要從這下手。

參考文章:
Spring的自動裝配
深入理解SpringBoot之自動裝配
P.S. 本文源碼是Spring Boot 1.3.7.RELEASE

1、@SpringBootApplication

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
//省略
}

@SpringBootApplication是個復合的注解,包括@EnableAutoConfiguration,@ComponentScan,@SpringBootConfiguration。通過源碼可以知道@SpringBootConfiguration本質(zhì)上是個@Configuration,由于@ComponentScan沒有指定掃描包,因此其默認掃描與該類同級的類或者同級包下的所有類。

2、@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
//省略
}

該注解就是開啟自動裝配功能,是自動裝配的核心注解。Spring會試圖在classpath下找到所有配置的bean,接著進行裝配。裝配過程中,會根據(jù)若干個Conditional條件(Spring4.X引入了@Conditional)定制規(guī)則來進行初始化。

@EnableAutoConfiguration主要是@Import(EnableAutoConfigurationImportSelector.class),引入EnableAutoConfigurationImportSelector.class,來看下其中的關(guān)鍵函數(shù)selectImports()

    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        try {
            AnnotationAttributes attributes = getAttributes(metadata);
            List<String> configurations = getCandidateConfigurations(metadata,
                    attributes);
            configurations = removeDuplicates(configurations);
            Set<String> exclusions = getExclusions(metadata, attributes);
            configurations.removeAll(exclusions);
            configurations = sort(configurations);
            recordWithConditionEvaluationReport(configurations, exclusions);
            return configurations.toArray(new String[configurations.size()]);
        }
        catch (IOException ex) {
            throw new IllegalStateException(ex);
        }
    }

從該函數(shù)可以看出,先從META-INF/spring-autoconfigure-metadata.properties獲取元數(shù)據(jù)與元數(shù)據(jù)之間的相關(guān)屬性,接著調(diào)用getCandidateConfigurations()函數(shù)

/**
     * Return the auto-configuration class names that should be considered. By default
     * this method will load candidates using {@link SpringFactoriesLoader} with
     * {@link #getSpringFactoriesLoaderFactoryClass()}.
     * @param metadata the source metadata
     * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
     * attributes}
     * @return a list of candidate configurations
     */
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
        return SpringFactoriesLoader.loadFactoryNames(
                getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    }

    /**
     * Return the class used by {@link SpringFactoriesLoader} to load configuration
     * candidates.
     * @return the factory class
     */
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }

在這里很巧遇到了SpringFactoriesLoader,他會獲取EnableAutoConfiguration.class中的配置。
接著selectImports函數(shù)將相關(guān)數(shù)據(jù)進行去重、過濾、排除,最后得到需要裝配的類。

3、invokeBeanFactoryPostProcessors

前面講了怎么獲取需要裝配的類,那么接下來探討下具體怎么裝配。
從抽象類AbstractApplicationContext的refresh()方法下手,refresh()方法中的invokeBeanFactoryPostProcessors(beanFactory)就是關(guān)鍵。
可以看出該方法是觸發(fā)BeanFactoryPostProcessors,那么跟進去看下

     /**
     * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
     * respecting explicit order if given.
     * <p>Must be called before singleton instantiation.
     */
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    }
    public interface BeanFactoryPostProcessor {

    /**
     * Modify the application context's internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for overriding or adding
     * properties even to eager-initializing beans.
     * @param beanFactory the bean factory used by the application context
     * @throws org.springframework.beans.BeansException in case of errors
     */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

來看下BeanFactoryPostProcessor接口的其中一種實現(xiàn)ConfigurationClassPostProcessor類(該類主要處理@Configuration注解)

/**
     * Derive further bean definitions from the configuration classes in the registry.
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        RootBeanDefinition iabpp = new RootBeanDefinition(ImportAwareBeanPostProcessor.class);
        iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME, iabpp);

        RootBeanDefinition ecbpp = new RootBeanDefinition(EnhancedConfigurationBeanPostProcessor.class);
        ecbpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(ENHANCED_CONFIGURATION_PROCESSOR_BEAN_NAME, ecbpp);

        int registryId = System.identityHashCode(registry);
        if (this.registriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException(
                    "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
        }
        if (this.factoriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException(
                    "postProcessBeanFactory already called on this post-processor against " + registry);
        }
        this.registriesPostProcessed.add(registryId);

        processConfigBeanDefinitions(registry);
    }

postProcessBeanDefinitionRegistry方法是將configuration配置類中派生出bean定義

/**
     * Build and validate a configuration model based on the registry of
     * {@link Configuration} classes.
     */
    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        //省略代碼
        // Parse each @Configuration class
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);

        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
        Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
        do {
            parser.parse(candidates);
            parser.validate();
             //省略代碼
    }

processConfigBeanDefinitions方法是基于@Configuration的類中構(gòu)建和校驗出配置的模型model,其中解析@Configuration關(guān)鍵類是ConfigurationClassParser,我們跟進去看下

public void parse(Set<BeanDefinitionHolder> configCandidates) {
        this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();

        for (BeanDefinitionHolder holder : configCandidates) {
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                if (bd instanceof AnnotatedBeanDefinition) {
                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                }
                else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                    parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
                }
                else {
                    parse(bd.getBeanClassName(), holder.getBeanName());
                }
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Exception ex) {
                throw new BeanDefinitionStoreException(
                        "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
            }
        }

        processDeferredImportSelectors();
    }

很巧的是,parse()方法最后會調(diào)用前面聊到的processDeferredImportSelectors()。

private void processDeferredImportSelectors() {
        List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
        this.deferredImportSelectors = null;
        Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);

        for (DeferredImportSelectorHolder deferredImport : deferredImports) {
            ConfigurationClass configClass = deferredImport.getConfigurationClass();
            try {
                String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
                processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Exception ex) {
                throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
                        configClass.getMetadata().getClassName() + "]", ex);
            }
        }
    }

processDeferredImportSelectors()中有句關(guān)鍵代碼
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
其中deferredImport為DeferredImportSelectorHolder類,

private static class DeferredImportSelectorHolder {

        private final ConfigurationClass configurationClass;

        private final DeferredImportSelector importSelector;

        public DeferredImportSelectorHolder(ConfigurationClass configurationClass, DeferredImportSelector importSelector) {
            this.configurationClass = configurationClass;
            this.importSelector = importSelector;
        }

        public ConfigurationClass getConfigurationClass() {
            return this.configurationClass;
        }

        public DeferredImportSelector getImportSelector() {
            return this.importSelector;
        }
    }

DeferredImportSelectorHolder內(nèi)部類中有DeferredImportSelector 的引用,到這里也就完成了整個自動裝配的所有操作。

小結(jié)

  1. 自動裝配歸根到底,是使用SpringFactoriesLoader來加載所有被@EnableAutoConfiguration修飾的類中的配置,通過selectImports函數(shù)將相關(guān)數(shù)據(jù)去重、過濾、排除,最終確定需要裝配的類;
  2. 當AbstractApplicationContext執(zhí)行refresh()方法時,其中的invokeBeanFactoryPostProcessors方法會觸發(fā)BeanFactoryPostProcessors去執(zhí)行自動裝配。
    比如處理@Configuration注解的ConfigurationClassPostProcessor類,其本身是BeanFactoryPostProcessors接口的具體實現(xiàn),通過ConfigurationClassParser.parse()調(diào)用processDeferredImportSelectors(),執(zhí)行DeferredImportSelector,來完成自動裝配。

Spring Boot自動裝配源碼分析就到這里了,建議讀者選擇其中關(guān)鍵源碼閱讀,再加上調(diào)試源碼加深理解。后面可能會不定期更新,有興趣的朋友可以在評論區(qū)一起討論研究。

最后有件很重要的事,那就是麻煩點贊關(guān)注贊賞,謝謝(??????)??

最后編輯于
?著作權(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)容