SpringBoot系列--自動裝配原理

Kuroko發表於2021-04-11

一、自動配置原理

1、原理圖

www.processon.com/diagraming/6072e...

2、原始碼入手

  • SpringBootApplication

SpringBoot系列--自動裝配原理
註解說明:
@Target(ElementType.TYPE)//設定當前註解可以標註在哪
@Retention(RetentionPolicy.RUNTIME)//標註註解的類編譯以什麼方式保留–執行時類,會被jvm載入
@Documented //生成java doc註解資訊
@Inherited //是否會被繼承
@SpringBootConfiguration //標註在某個類上,標識這是一個SpringBoot配置類
@EnableAutoConfiguration //標識這是一個配置類;配置類也是容器中的一個元件
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), //掃描包
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
FilterType:spring對外提供的擴充套件類,可以按照我們的意願進行排除
AutoConfigurationExcludeFilter:排除所有配置類並且是自動配置類中裡面的其中一個

我們進入註解—>@EnableAutoConfiguration

SpringBoot系列--自動裝配原理

@AutoConfigurationPackage,作用是將當前配置類所在的包儲存在BasePackages的Bean中,供Spring內部使用

@Import 關鍵註解
可以看到,在@EnableAutoConfiguration註解內使用到了@import註解來完成匯入配置的功能,而EnableAutoConfigurationImportSelector 實現了DeferredImportSelectorSpring內部在解析@Import註解時會呼叫getAutoConfigurationEntry方法

SpringBoot系列--自動裝配原理
如下程式碼的getCandidateConfigurations方法

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
            AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        }
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        configurations = removeDuplicates(configurations);
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = filter(configurations, autoConfigurationMetadata);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationEntry(configurations, exclusions);
    }

getCandidateConfigurations方法中的SpringFactoriesLoader.loadFactoryNames.loadFactoryNames.loadSpringFactories方法中進行掃描具有META-INF/spring.factories檔案的jar包。

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }

        try {
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }

@EnableAutoConfiguration註解通過@SpringBootApplication被間接的標記在了Spring Boot的啟動類上。在SpringApplication.run(…)的內部就會執行selectImports()方法,找到所有JavaConfig自動配置類的全限定名對應的class,然後將所有自動配置類載入到Spring容器中

如下為SpringBoot自動配置原理圖
自動配置原理圖

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章