我是如何做到springboot自動配置原理解析


一前言

springboot 2.0.0版本分析,整體的自動配置流程如下:

在這里插入圖片描述

具體配置參考官方文檔:springboot-doc

二 @SpringBootApplication

核心注解@SpringBootConfiguration其實就是@Configuration注解,表示是個配置類;@EnableAutoConfiguration表示springboot的自動配置機制;@ComponentScan表示掃描允許注冊額外的配置類;

@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan

Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

	// 排除不會被應用的自動配置類,classes形式
	@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
	Class<?>[] exclude() default {};

	// 排除不會被應用的自動配置類,字符串數組形式
	@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
	String[] excludeName() default {};

	// 掃描基本包
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	// 掃描基本類
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

}

三 AutoConfigurationImportSelector

點擊@EnableAutoConfiguration 注解進入,看見@Import({AutoConfigurationImportSelector.class})是導入AutoConfigurationImportSelector類;

AutoConfigurationImportSelector 類是自動配置的核心類,其主要進行配置的功能是配置factory.propertiesspring內嵌集成引入的配置;

3.1 具體依賴圖如下:

在這里插入圖片描述

3.2 成員

	// 表示不引入配置
	private static final String[] NO_IMPORTS = new String[0];
	// 配置日志
    private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
    // 排除的自動配置
    private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
    // 聲明 beanFactory
    private ConfigurableListableBeanFactory beanFactory;
    // 聲明 environment (全局環境)
    private Environment environment;
    // 聲明 beanClassLoader (bean的類加載器,加載spring-autoconfigure-metadata.properties中集成類)
    private ClassLoader beanClassLoader;
    // 聲明 resourceLoader (資源加載器,加載spring的 factory.properties配置類)
    private ResourceLoader resourceLoader;

3.3 selectImports

selectImports 這個方法的主要功能就是導入factory.propertiesspring-autoconfigure-metadata.properties中的配置類;

 public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            try {
          	  // 1 加載元數據信息,本質就是加載bean,這里的bean是指我我們spring-autoconfigure-metadata.properties中集成類
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                // 2 AnnotationAttributes本質是個map
                AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                // 3  獲得 spring.factories 中的配置類
                List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                // 4  配置類復制用於排序不需要的配置類
                configurations = this.removeDuplicates(configurations);
                //  優先級排序
                configurations = this.sort(configurations, autoConfigurationMetadata);
                // 需移除配置類
                Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                // 校驗移除
                this.checkExcludedClasses(configurations, exclusions);
                // 執行移除配置類
                configurations.removeAll(exclusions);
                configurations = this.filter(configurations, autoConfigurationMetadata);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return StringUtils.toStringArray(configurations);
            } catch (IOException var6) {
                throw new IllegalStateException(var6);
            }
        }
    }

1 分析
AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);

進入方法發現加載的元數據信息的路徑是 META-INF/spring-autoconfigure-metadata.properties

public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
        return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
    }

在自動配置包底下找到spring-autoconfigure-metadata.properties

在這里插入圖片描述
點進屬性文件發現都spring自動配置類名的配置信息,部分如下:

#Thu Mar 01 04:46:13 UTC 2018
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration=
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration.Configuration=
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,org.springframework.data.cassandra.core.ReactiveCassandraTemplate,reactor.core.publisher.Flux
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration.ConditionalOnClass=org.apache.solr.client.solrj.SolrClient,org.springframework.data.solr.repository.SolrRepository
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration=
............................

我們隨意點開其中的一個配置類,比如第一個HttpMessageConvertersAutoConfiguration,其中的class注解如下,可以發現其自動配置類都是通過注解配置;

// 表示配置類相當於xml中的 bean標簽
@Configuration
// 判定是否存在HttpMessageConverter.class類,如果不存在則引入
@ConditionalOnClass({HttpMessageConverter.class})
// 在這三個配置類配置之后再進行配置
@AutoConfigureAfter({GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class})
// 導入配置類相當於xml中的 import標簽
@Import({JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class, JsonbHttpMessageConvertersConfiguration.class})
public class HttpMessageConvertersAutoConfiguration {

3 分析

this.getCandidateConfigurations(annotationMetadata, attributes);方法的主要功能是獲取候選配置;

進入getCandidateConfigurations方法發現里面的主要方法是loadFactoryNames;

// 獲得factory配置信息類名
 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

進入 loadFactoryNames 方法 主要是2部分;第一個是loadSpringFactories(classLoader),第二個是getOrDefault

// 加載factory類名
 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        //  返回類名的list
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

第一部分:
loadSpringFactories本質就是使用spring的Resource資源調用獲得 spring.factories 中的配置類;

// 加載spring.factories中的配置類信息
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
            	// 獲得 `spring.factories` 配置類的URL
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();
				// 將 `spring.factories`  每個配置類的key 和 val 存儲進 map
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
                        result.addAll((String)entry.getKey(), factoryClassNames);
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var9) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
            }
        }
    }

classLoader.getResources("META-INF/spring.factories") ;中找到自動配置包中的配置如下圖:
在這里插入圖片描述

spring.factories裝載配置類部分信息如下,沒錯這些配置都是sping啟動需要的配置類信息,監聽器,過濾器,自動配置的start配置類,以及啟動的失敗的錯誤分析還有模板引擎的支持,詳細大家翻下配置包即可;

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
....................................

第二部分:
getOrDefault是個Map集合,map中有這個key時,就使用這個key值,如果沒有就使用默認值defaultValue,返回也就是類名的list;

在這里插入圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM