Back to Javatutorial

SpringBoot自动装配(一):加载自动装配类

docs/Spring全家桶/SpringBoot源码解析/SpringBoot自动装配(一):加载自动装配类.md

1.0.015.5 KB
Original Source

Զװ springboot ĺ֮һĽ̽ springboot μԶװġ

@SpringBootApplication עһУᵽ springboot Զװע @EnableAutoConfiguration£

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// Զװİ
@AutoConfigurationPackage
// Զװ
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    /**
     * жųԶװ
     */
    Class<?>[] exclude() default {};

    /**
     * жųԶװ
     */
    String[] excludeName() default {};

}

ϴ֣

  1. @AutoConfigurationPackageָԶװİ
  2. @Import(AutoConfigurationImportSelector.class)ԶװĴ AutoConfigurationImportSelectorԶװĹؼڣ
  3. @EnableAutoConfiguration ԣ@EnableAutoConfiguration ṩԣexclude excludeNameųҪԶװࡣ

ص AutoConfigurationImportSelector

1. AutoConfigurationImportSelector.AutoConfigurationGroup

AutoConfigurationImportSelector ʵ DeferredImportSelector DeferredImportSelector ķԲο ConfigurationClassPostProcessor ֮ @Import עֱӸۣ

  • DeferredImportSelector ImportSelector ӽӿڣڲһӿ Groupýӿڶ

    public interface DeferredImportSelector extends ImportSelector {
        ...
    
        interface Group {
    
            /**
             * 
             */
            void process(AnnotationMetadata metadata, DeferredImportSelector selector);
    
            /**
             * ص
             */
            Iterable<Entry> selectImports()
        }
    }
    
    

    ڴ DeferredImportSelector ĵʱDeferredImportSelector.Group#process ȵãȻٵ DeferredImportSelector.Group#selectImports صࣻ

  • DeferredImportSelector ָķ飬ڴʱ԰鴦ࣻ

  • DeferredImportSelector ڴʱȽఴһ map Уڴࣨspring Ϊ @Component``@ComponentScan``@Import``@Configuration``@Bean ǵࣩеĵ࣬Ҳ˵DeferredImportSelector ࣬עᵽ beanFactory кٽעᣨעǰжܷעᵽ beanFactoryܲעᣩ

AutoConfigurationImportSelector Ĵ룺

// ʵ DeferredImportSelector
public class AutoConfigurationImportSelector implements DeferredImportSelector, 
        BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

    ...

    /**
     * ʵ DeferredImportSelector.Group
     */
    private static class AutoConfigurationGroup implements DeferredImportSelector.Group, 
            BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {

        /**
         * 浼
         */
        private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();

        /**
         * 
         */
        @Override
        public void process(AnnotationMetadata annotationMetadata, 
                DeferredImportSelector deferredImportSelector) {
            Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
                    () -> String.format("Only %s implementations are supported, got %s",
                            AutoConfigurationImportSelector.class.getSimpleName(),
                            deferredImportSelector.getClass().getName()));
            // 1\.  AutoConfigurationImportSelector#getAutoConfigurationEntry(...) 
            // Զװ
            AutoConfigurationEntry autoConfigurationEntry = 
                ((AutoConfigurationImportSelector) deferredImportSelector)
                    .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
            // 2\. ȡ autoConfigurationEntry 
            this.autoConfigurationEntries.add(autoConfigurationEntry);
            for (String importClassName : autoConfigurationEntry.getConfigurations()) {
                this.entries.putIfAbsent(importClassName, annotationMetadata);
            }
        }

        /**
         * ص
         */
        @Override
        public Iterable<Entry> selectImports() {
            if (this.autoConfigurationEntries.isEmpty()) {
                return Collections.emptyList();
            }
            // 3\. õ
            Set<String> allExclusions = this.autoConfigurationEntries.stream()
                    .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream)
                    .collect(Collectors.toSet());
            // 4\.  autoConfigurationEntries תΪ LinkedHashSet
            Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
                    .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
                    .collect(Collectors.toCollection(LinkedHashSet::new));
            // 5\. ȥҪ˵
            processedConfigurations.removeAll(allExclusions);
            // 6\. 
            return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata())
                    .stream().map((importClassName) -> new Entry(
                        this.entries.get(importClassName), importClassName))
                    .collect(Collectors.toList());
        }

        ...
    }

}

ǽ DeferredImportSelector.Group#process DeferredImportSelector.Group#selectImports ܽ:

  1. AutoConfigurationImportSelector#getAutoConfigurationEntry(...) Զװࣻ
  2. õԶװౣ浽 autoConfigurationEntries У
  3. õ࣬Щ @EnableAutoConfiguration exclude excludeName ָģ
  4. autoConfigurationEntries תΪ LinkedHashSetΪ processedConfigurations
  5. ȥ processedConfigurations Ҫ˵ࣻ
  6. 5 õ󣬷ء

ǶЩؼз

ر˵DeferredImportSelector ImportSelector ӽӿڣImportSelector ķ selectImports(...) DeferredImportSelector Ҳд˸÷

ҲǼԶװ࣬յ࣬Ҫעǣspringboot Զ****ﴦģ㣬ڷڴϵ㣬Ȼͻᷢûе

£springboot Զ**** AutoConfigurationImportSelector#selectImports дģ AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports дġ

2. ȡװࣺAutoConfigurationImportSelector#getAutoConfigurationEntry

Զ ļشΪ

AutoConfigurationEntry autoConfigurationEntry = 
    ((AutoConfigurationImportSelector) deferredImportSelector)
        .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);

ôԶװģֱӽ AutoConfigurationImportSelector#getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(
        AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
    // һжǷԶװ
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    // ȡע
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 1\. غѡԶ
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 2\. ȥأתsetתlist
    configurations = removeDuplicates(configurations);
    // 3\. ȥҪų࣬ʵǴ@EnableAutoConfigurationexcludeexcludeName
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    // 4\. ˲ҪԶװ
    configurations = filter(configurations, autoConfigurationMetadata);
    // 5\.  AutoConfigurationImportEvent ¼
    fireAutoConfigurationImportEvents(configurations, exclusions);
    // 6\. շصֵ
    return new AutoConfigurationEntry(configurations, exclusions);
}

dzҪ˻ȡԶװȫò£

  1. غѡԶװ࣬springboot Զװλ classpath µ META-INF/spring.factories ļУkey Ϊ org.springframework.boot.autoconfigure.EnableAutoConfigurationǺϸ

  2. ȥظԶװ࣬һصõԶװܻظȥظ࣬ȥʽҲdz򵥣springboot ֻת Setת List

  3. ȥų࣬ǰᵽ @EnableAutoConfiguration ͨ exclude excludeName ָҪų࣬һԵģ

  4. ˲ҪԶװ࣬ݱ˵ԣֲûɹˣ

    ǰ 124

    ˺ 124

  5. AutoConfigurationImportEvent ¼

  6. 3 õų 4 õԶװװ AutoConfigurationEntry ء

עһд룺

// 6\. շصֵ
return new AutoConfigurationEntry(configurations, exclusions);

configurations exclusions AutoConfigurationEntry Ĺ췽 AutoConfigurationEntry

protected static class AutoConfigurationEntry {
    // Զװ
    private final List<String> configurations;

    // ҪųԶװ
    private final Set<String> exclusions;

    /**
     * 췽߽иֵ
     */
    AutoConfigurationEntry(Collection<String> configurations, Collection<String> exclusions) {
        this.configurations = new ArrayList<>(configurations);
        this.exclusions = new HashSet<>(exclusions);
    }

    ...
}

Щɼշص AutoConfigurationEntry ݣ

  • configurationsԶװ࣬ѾȥҪų
  • exclusionsͨ @EnableAutoConfiguration ָҪų

ԶװĻȡˣغѡԶװ̡

3. غѡԶװ

Զװļλ AutoConfigurationImportSelector#getCandidateConfigurations£

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, 
        AnnotationAttributes attributes) {
    // õ spring ṩķSpringFactoriesLoader.loadFactoryNames(...)
    // getSpringFactoriesLoaderFactoryClass() صEnableAutoConfiguration
    List<String> configurations = SpringFactoriesLoader
            .loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    Assert.notEmpty(configurations, "...");
    return configurations;
}

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}

SpringFactoriesLoader#loadFactoryNames

public final class SpringFactoriesLoader {

    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        // õ factoryTypeName  org.springframework.boot.autoconfigure.EnableAutoConfiguration
        String factoryTypeName = factoryType.getName();
        return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    /**
     * мأص META-INF/spring.factories е
     */
    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }

        try {
            //  META-INF/spring.factories 
            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);
                //  META-INF/spring.factories תΪ Properties 
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    // StringUtils.commaDelimitedListToStringArray(...) ŷָΪ
                    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);
        }
    }
    ...
}

Կص classpath µ META-INF/spring.factories ļע⣺ļܻжλڲͬ jar С

springboot Դ META-INF/spring.factories λ spring-boot-autoconfigure ģ£

һ spring.factories

ļ࣬ key-value ʽ棬ֵ֮ʹ , ֿᵽԶװ key org.springframework.boot.autoconfigure.EnableAutoConfigurationӦ value dz࣬Ͳչʾˡ

һ֮Զװͱעᵽ spring ˡעʱص spring еĻ BeanDefinitionҪΪ spring beanþ ConditionalOnBean``ConditionalOnClass עĿ飬ЩǺٷ

4. ȡԶװĴ

ٻص AutoConfigurationImportSelector.AutoConfigurationGroupڵ 1 ܽ£

  1. AutoConfigurationImportSelector#getAutoConfigurationEntry(...) Զװࣻ
  2. õԶװౣ浽 autoConfigurationEntries У
  3. õ࣬Щ @EnableAutoConfiguration exclude excludeName ָģ
  4. autoConfigurationEntries תΪ LinkedHashSetΪ processedConfigurations
  5. ȥ processedConfigurations Ҫ˵ࣻ
  6. 5 õ󣬷ء

ϵ 2 3 ڣԶļع̣IJ衣

Ŵ룬ǻֽᷢIJ趼Ƚϼ򵥣Ҳһ˵°ɡ

  • 2 õԶװֻ࣬ǵ List#add(...) õ autoConfigurationEntryautoConfigurationEntriesAutoConfigurationGroup ijԱ AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports лõ

  • 3 õеĹ࣬ùDZ autoConfigurationEntriesȻͨ autoConfigurationEntry#getExclusions õ ǰҲᵽautoConfigurationEntry ֻԱconfigurations(ȥųԶװ) exclusions@EnableAutoConfiguration ָų)

  • 4 List תΪ LinkedHashSet

  • 5 еԶװٽһȥųIJųĶеų࣬ӦǻͬһĿж @EnableAutoConfiguration һ @EnableAutoConfiguration עų A``B ࣬ڶ @EnableAutoConfiguration עų C``D ࣬ų A``B``C``D ĸࣻ

  • 6 һҪ˳Զװעᵽ beanFactory е˳AutoConfigureOrder``@AutoConfigureAfter @AutoConfigureBefore ﴦģݣԲο springboot Զװ֮Զװ˳.

ЩԶװĻȡˡ

5. ԶԶװ

˽Զװļع̺ҲԶһԶװࡣ

  1. ׼һԶװ
@Configuration
public class MyAutoConfiguration {

    @Bean
    public Object object() {
        System.out.println("create object");
        return new Object();
    }
}

ܼ򵥣һ @Configuration ࣬ʹ @Bean עⴴһ beanڴ bean Ĺл ӡ "create object"

  1. ׼ META-INF/spring.factories £
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.learn.autoconfigure.demo01.configure.MyAutoConfiguration

@SpringBootApplication
public class AutoconfigureDemo01Application {

    public static void main(String[] args) {
        SpringApplication.run(AutoconfigureDemo01Application.class, args);
    }

}

н£

Կcreate object ɹӡˡ

bean ͨɨ贴ģԶװ䵼أͨԵķʽԶװõࣺ

ԿMyAutoConfiguration Զװбˡ

ע⵽MyAutoConfiguration @Configuration ע⣬ ô sping ɨ赽ģԶװõأ

springboot Դ@SpringBootApplication עһУᵽ SpringBootApplication עе @ComponentScan ָһAutoConfigurationExcludeFilterԶװ࣬ǿĿǰΪֹ beanFactory Щ beanName

Կû MyAutoConfiguration˴ʱûɨ beanFactory С

ȻҲ԰ MyAutoConfiguration @Configuration עȥͲˡ

6. ܽ

Ĵ @EnableAutoConfiguration עԶװļ̣ AutoConfigurationImportSelector#getAutoConfigurationEntry Уռص META-INF/spring.factories ļ key org.springframework.boot.autoconfigure.EnableAutoConfiguration

õԶװspring ὫעᵽУʱǻһ BeanDefinitionҪΪ spring beanþ ConditionalOnBean``ConditionalOnClass עĿ飬ЩǺٷ


ԭӣhttps://my.oschina.net/funcy/blog/4870868 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע