Spring Boot @EnableAutoConfiguration解析

Just do the back-end development, when the first contact is the basis of the spring, to quote a two-way package provides bean, also we need to increase the corresponding packet in the xml <context:component-scan base-package="xxx" /> or add notes @ComponentScan({ "xxx"}). I felt very urgly, but did not go to study there a better way.

After the contact until the Spring Boot, bean found to be automatically incorporated second party package. But I did not see the realization of this principle. Until recently, when asked about the interview. So I looked under implementation logic.

 

Use gestures

Under the first principle speaks before use posture.

Bean defined in a project A in.

package com.wangzhi;

import org.springframework.stereotype.Service;

@Service
public class Dog {
}

 

And the project is resources/META-INF/to create a named under the spring.factoriesdocument, the document reads as follows

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.wangzhi.Dog

 

Then reference project A jar package in the project B.

projectA code is as follows:

package com.wangzhi.springbootdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@EnableAutoConfiguration
public class SpringBootDemoApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringBootDemoApplication.class, args);
        System.out.println(context.getBean(com.wangzhi.Dog.class));
    }

}

 

Print Results:

com.wangzhi.Dog@3148f668

 

Analytical principle

Overall is divided into two parts: First, collect all spring.factoriesof the EnableAutoConfigurationrelevant class of the bean, the second is to get the class registration to spring container.

Class collection bean definition

In the spring when the container starts, it will call toAutoConfigurationImportSelector#getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(
        AutoConfigurationMetadata autoConfigurationMetadata,
        AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    // EnableAutoConfiguration注解的属性:exclude,excludeName等
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 得到所有的Configurations
    List<String> configurations = getCandidateConfigurations(annotationMetadata,
            attributes);
    // 去重
    configurations = removeDuplicates(configurations);
    // 删除掉exclude中指定的类
    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会调用到方法loadFactoryNames:

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        // factoryClassName为org.springframework.boot.autoconfigure.EnableAutoConfiguration
        String factoryClassName = factoryClass.getName();
        // 该方法返回的是所有spring.factories文件中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的类路径
        return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }


public static final String FACTORIES_RESOURCE_LOCATION = "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();
                Resource a UrlResource = new new a UrlResource (url);
                 // read the file contents, properties similar to HashMap, including key attributes and value 
                the Properties the Properties = PropertiesLoaderUtils.loadProperties (Resource);
                 for (Map.Entry <? ?,> entry: properties.entrySet ()) { 
                    String factoryClassName = . ((String) entry.getKey ()) TRIM ();
                     // the attribute file can be used ',' a plurality of divided value 
                    for (String factoryName: StringUtils.commaDelimitedListToStringArray ((String ) entry.getValue ())) {  
                        result.add (factoryClassName, factoryName.trim ());
                    } 
                } 
            }
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }

 

Sign up to container

All obtained in the above process in spring.factoriesthe class specified in the path of the bean, the processGroupImportsprocess will be processed @import logic which annotations introduced into the same vessel.

public  void processGroupImports () {
     for (DeferredImportSelectorGrouping GROUPING: the this .groupings.values ()) {
         // getImports i.e. class that encapsulates all the paths obtained above 
        grouping.getImports () forEach (entry ->. { 
            ConfigurationClass configurationClass = the this .configurationClasses .get ( 
                    entry.getMetadata ()); 
            the try {
                 // and process annotations as @Import 
                processImports (configurationClass, asSourceClass (configurationClass), 
                        asSourceClasses (entry.getImportClassName ()), to false  );
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                        "Failed to process import candidates for configuration class [" +
                                configurationClass.getMetadata().getClassName() + "]", ex);
            }
        });
    }
}

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
            Collection<SourceClass> importCandidates, Boolean         processConfigurationClass (candidate.asConfigClass (the configClass));checkForCircularImports) { 
    ... 
    // traverse collected classpath 
    for (SourceClass candidate: importCandidates) { 
       ... 
        // If the candidate is ImportSelector ImportBeanDefinitionRegistrar or the type of processing logic will be different, here not concerned
          // Candidate class Not AN or ImportBeanDefinitionRegistrar ImportSelector ->
                         // process class IT AS AN @Configuration 
                        the this .importStack.registerImport ( 
                                . currentSourceClass.getMetadata (), candidate.getMetadata () the getClassName ()); 
        // as @Configuration processing             

   ... 
} 
            
    .. . 
}

 

It can be seen in the bean class definition first step collected will eventually be to Configurationthe same treatment registered to the vessel.

End

@EnableAutoConfigurationAnnotations second party introduced simplified bean package cost. A second party contracted to provide other applications, only the second party bag exposed to the external bean definitions in spring.factoriesjust fine. For unwanted bean, consumers can use @EnableAutoConfigurationthe excludeexclusion properties.

 

I compiled a free Java Advanced information, covering Java, Redis, MongoDB, MySQL, Zookeeper, Spring Cloud, Dubbo distributed high concurrency and other tutorials, a total of 30G, needs its own collection.
Portal: https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q

Guess you like

Origin www.cnblogs.com/yuxiang1/p/11331727.html