SpringBoot source parsing (e) ----- core competencies Spring Boot - Automatic configuration parsing source code

It analyzed on a blog springBootto start the process, general outline tip of the iceberg. Look at today springBoot's highlights features: automated assembly function.

Start with the @SpringBootApplicationbeginning. In the startup process section, we describe the SpringBoot2 rough start step, and explain the source. But this was not deployed to refresh the container, refreshContext (context); a simple line of code behind it to do too many things. So in order not overwhelming herein, this method also try to select and related notes @SpringBootApplication explain.

springBoot start class loader

First, load the spring springBoot startup class poured into the vessel beanDefinitionMap, load look prepareContext method method: load (context, sources.toArray (new Object [0]));
follow will eventually execute the method of BeanDefinitionLoader load method:

private int load(Object source) {
    Assert.notNull (Source, "not the MUST BE null Source" );
     // If this is the type of class, to enable annotation type 
    IF (Source instanceof Class <?> {)
         Return the Load ((Class <?> ) Source);
    }
    // If the resource type is enabled xml parsing 
    IF (Source the instanceof the Resource) {
         return Load ((the Resource) Source);
    }
    // If a package type, package enable scanning, for example: @ComponentScan 
    IF (Source the instanceof the Package) {
         return Load ((the Package) Source);
    }
    // If the type is a string loaded directly 
    IF (Source the instanceof CharSequence) {
         return Load ((CharSequence) Source);
    }
    throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

Continue to follow up load(Class<?> source)method:

The above-described method of determining whether the starting class contains @component annotations, we can not start the annotation category. Follow up will find, AnnotationUtils determine whether to include the comment by recursive implementation, notes on the notes contained if the specified type is also possible.

Start class contains @SpringBootApplication notes, find @SpringBootConfiguration further comment, and then find @Component notes, will eventually find @Component notes:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
}

Found in @Componentthe annotation, the surface of the object is a spring bean, which then will be packaged in the information beanDefinitaion, beanDefinitionMap added to the container. as follows:

In this way, we start the class was packed into AnnotatedGenericBeanDefinitiona processing subsequent start classes are based on the object of.

@EnableAutoConfiguration

@SpringBootApplication annotation entry contains annotations automatically configured:

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}

We now look into @EnableAutoConfiguration

@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

@AutoConfigurationPackage

  • Automatic configuration package comment
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}

@Import (AutoConfigurationPackages.Registrar.class): All components primary package configuration class (@SpringBootApplication) located inside the package and its sub-scan to the default Spring container. as follows

@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
         // default master class configuration will scan @SpringBootApplication labeled package and its sub-packets where all components 
        Register (Registry, new new packageimport (Metadata) .getPackageName ());
    }

    @Override
    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.<Object>singleton(new PackageImport(metadata));
    }
}

@Import(EnableAutoConfigurationImportSelector.class)

EnableAutoConfigurationImportSelector: Import which the selector assembly, all components need to be imported to the full class name returns manner, these components will be added to the container.

 1 //EnableAutoConfigurationImportSelector的父类:AutoConfigurationImportSelector
 2 @Override
 3 public String[] selectImports(AnnotationMetadata annotationMetadata) {
 4     if (!isEnabled(annotationMetadata)) {
 5         return NO_IMPORTS;
 6     }
 7     try {
 8         AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
 9             .loadMetadata(this.beanClassLoader);
10         AnnotationAttributes attributes = getAttributes(annotationMetadata);
11         List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
12         configurations = removeDuplicates(configurations);
13         configurations = sort(configurations, autoConfigurationMetadata);
14         Set<String> exclusions = getExclusions(annotationMetadata, attributes);
15         checkExcludedClasses(configurations, exclusions);
16         configurations.removeAll(exclusions);
17         configurations = filter(configurations, autoConfigurationMetadata);
18         fireAutoConfigurationImportEvents(configurations, exclusions);
19         return configurations.toArray(new String[configurations.size()]);
20     }
21     catch (IOException ex) {
22         throw new IllegalStateException(ex);
23     }
24 }

We mainly look at the first 11 rows List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);will vessel is filled to a large number of automatic configuration class (xxxAutoConfiguration), this scenario is to import all the components required for container and configure these components. After obtaining these components, but also filter about these components, we look into it with

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    //...
    return configurations;
}

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

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

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    FactoryClassName String = factoryClass.getName ();
     the try {
         // loaded from the class path META-INF / spring.factories automatically configure all the default class 
        the Enumeration <the URL> = URLs (classLoader =! Null ? ClassLoader.getResources (FACTORIES_RESOURCE_LOCATION) :
                                 ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        List<String> result = new ArrayList<String>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            The Properties the Properties = PropertiesLoaderUtils.loadProperties ( new new a UrlResource (url));
             // Get all values EnableAutoConfiguration specified, the value of which is EnableAutoConfiguration.class 
            String factoryClassNames = Properties.getProperty (factoryClassName);
            result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
        }
        return result;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}

SpringBoot start time obtained from the META-INF / spring.factories class path EnableAutoConfiguration specified value, and these values ​​are automatically configured as the class into a container, automatic configuration classes take effect, and finally complete the automatic configuration. EnableAutoConfiguration default spring-boot-autoconfigure this package, as FIG.

96 eventually autoconfiguration and the class is loaded into register Spring container

We may also need to write the automatic configuration file Bean

Custom starter

Defining a first class module configuration:

@Configuration
@ConditionalOnProperty(name = "enabled.autoConfituration", matchIfMissing = true)
public class MyAutoConfiguration {

    static {
        System.out.println("myAutoConfiguration init...");
    }

    @Bean
    public SimpleBean simpleBean(){
        return new SimpleBean();
    }

}

Then define a starter module, which no code, and without any dependency POM, only a built below the META-INF  spring.factoriesfile, add the following configuration:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
spring.study.startup.bean.MyAutoConfiguration

as the picture shows:

Finally, just to introduce our starter module can be started in pom class project.

principle

Eventually AutoConfigurationImportSelectorparse spring.factoriesfile:

SpringBoot configuration class provides us with more than 180, but we can not all be introduced. @Conditional annotation conditional judgment or @ConditionalOnProperty other related annotations, decide whether to assemble.

Our custom configuration classes are assembled in the same logic, we specify the following comments:

@ConditionalOnProperty(name = "enabled.autoConfituration", matchIfMissing = true)

The default is true, so the starter custom successful implementation.

 

 

Guess you like

Origin www.cnblogs.com/java-chen-hao/p/11837043.html