1. Analysis of POm. XML

The core depends on

  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.4.5</version>
<! -- Parent project -->
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.4.5</version>
Copy the code

Spring-boot-dependencies are the parent project of spring-boot-starter-parent, so you don’t need to specify the version of the Spring Boot dependencies when you introduce them.

Initiator: indicates the Spring Boot startup scenario

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
Copy the code
  • Spring-boot-starter -web, for example, will automatically import all of our web environment dependencies
  • Spring Boot turns all scenarios into individual initiators
  • What function can we use if we just need to find the corresponding starter

2, @springBootApplication analysis

Start the class:

package com.cheng;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Springboot01HelloworldApplication {

    public static void main(String[] args) {
        // Start the Spring Boot application
        SpringApplication.run(Springboot01HelloworldApplication.class, args);// Reflection mechanism}}Copy the code

@SpringBootApplication

The @springBootApplication annotation indicates that this class is the main configuration class of SpringBoot. It is by adding the @SpringBootApplication annotation that SpringBoot application can be started.

The @SpringBootApplication annotation is a “three-body” structure, which is actually a composite annotation. Click to see the @SpringBootApplication annotation component:

@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 {
Copy the code

Although its definition uses multiple annotations for meta-annotation, there are actually only three annotations that are important to a SpringBoot application, and the “three-body” structure actually refers to these three annotations:

  • @SpringBootConfiguration: This annotation on a class indicates that the class is a SpringBoot configuration class
  • @EnableAutoConfiguration: This annotation is the key to springBoot’s automatic configuration, and it is very important
  • @ComponentScan : Scan the packages in the same directory as the main startup class, assemble the scanned classes into the Spring container, and hand over to the Spring container to host

Analysis of @ SpringBootConfiguration

There are only two important annotations in the @springBootConfiguration source code

  • @Configuration: Indicates that the startup class is the Spring configuration class
  • @ComponentThis is also a Spring component

Analyze @enableAutoConfiguration

Click to see the composition of @EnableAutoConfiguration and see that it is also a composite annotation

@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 {};
}
Copy the code

The Spring source code has many Enable annotations that use the @import annotation to collect and register scenario-specific beans and load them into the Spring container.

The @enableAutoConfiguration function is to collect all the bean definitions that meet the autoconfiguration criteria and load them into the Spring container with the @import annotation.

Two important comments in the @enableAutoConfiguration composite annotation:

  • == first: @autoconfiguration package == : AutoConfigurationPackage. The source code is as follows

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import(AutoConfigurationPackages.Registrar.class)
    public @interface AutoConfigurationPackage {
    Copy the code

    Found @ AutoConfigurationPackage is a combination of annotations, is one of the most important note: @ Import (AutoConfigurationPackages. The Registrar. The class) : == @import is Spring’s underlying annotation that imports a component into the container ==; Such as @ Import (AutoConfigurationPackages. The Registrar. The class), it is registered with the Registrar of the component class container, to see the Registrar registerBeanDefinitions method in the class, This method is the concrete implementation of the import component class

    	    @Override
            //AnnotationMetadata (AnnotationMetadata contains information on which annotations are used and on which class the corresponding annotation is applied)
    		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
                 // Pass in the annotated meta information and get the corresponding package name
    			register(registry, new PackageImport(metadata).getPackageName());
    		}
    Copy the code

    The @AutoConfigurationPackage annotation scans all the components in the packages and subpackages annotated by the main configuration class (@SpringBootApplication) into the Spring container.

    When developing projects using SpringBoot, you need to create classes in all packages and subpackages annotated by (@SpringBootApplication) so that SpringBoot can add all components to the Spring container.

  • * * the second: = = = = @ Import (AutoConfigurationImportSelector. Class) : * * will AutoConfigurationImportSelector this class into the spring container, AutoConfigurationImportSelector can help springboot applications will all eligible @ Configuration Configuration is loaded into the current springboot create and use the spring container (ApplicationContext ).

    View AutoConfigurationImportSelector source code, this class is through the analysis of the source told the Spring by selectImports method Boot is what you need to import components

    	@Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    		if(! isEnabled(annotationMetadata)) {return NO_IMPORTS;
    		}
            // Get the autoconfigured entity
    		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
    		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    	}
    Copy the code

    Continue to analyze AutoConfigurationImportSelector source code

Point in view getCandidateConfigurations method

SpringBoot gets the value of EnableAutoConfiguration (i.e., the initiator) from the meta-INF /spring.factores in the classpath at boot time and imports it into the container as an autoconfiguration class. The autoconfiguration class takes effect to help us do the autoconfiguration work

// Get the candidate configuration
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {. List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), 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;
	}

Copy the code

GetCandidateConfigurations loadFactoryNames method has an important method, this method need to two parameters:

GetSpringFactoriesLoaderFactoryClass () and getBeanClassLoader ()

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

    protected ClassLoader getBeanClassLoader(a) {
		return this.beanClassLoader;
	}
Copy the code
  1. GetSpringFactoriesLoaderFactoryClass (). This method returns the EnableAutoConfiguration class

  2. This method getBeanClassLoader() returns a beanClassLoader

Click on the source code for the loadFactoryNames and loadSpringFactories methods:

    public static List<String> loadFactoryNames(Class<? > factoryClass,@Nullable ClassLoader classLoader) {
        
        // Get the keys in and out
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    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 {              
                // Load the FACTORIES_RESOURCE_LOCATION file in the classpath and encapsulate the full path information of the configuration class as an Enumeration object
               Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
                // Loop the Enumeration class object, generate the Properties object according to the corresponding node information, obtain the value through the passed key, and then cut the value into a small string and convert it into the Array, method result set
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    // All resources are loaded into the configuration class
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) { Entry<? ,? > entry = (Entry)var6.next(); String factoryClassName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryName = var9[var11];
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }
                cache.put(classLoader, result);
                return result;
Copy the code

Key functionality is provided by @import, Its import AutoConfigurationImportSelector selectImports () method. Through SpringFactoriesLoader loadFactoryNames () scan all has the meta-inf/spring. The fac The Tories’ JAR. The spring-boot-autoconfigure-x.x.x.x.jar file contains such a spring.factories. This file contains all the autoconfigurator classes.

,

@Import(AutoConfigurationImportSelector.class)When SpringBoot starts, it gets the value of EnableAutoConfiguration from the meta-INF /spring.factores in the classpath and imports it into the container as an autoconfiguration class. Help us with the auto-configuration.

Conclusion: All the autoconfiguration classes are scanned and loaded at startup. All the autoconfiguration classes are in the spring-boot-autoconfigure-2.4.5.jar–> meta-INF directory with the spring.factories file, but they don’t always work. To see whether start is imported, as long as the corresponding start is imported, there is a corresponding initiator, with the initiator, our autoload class will take effect, and then the automatic configuration is successful.

Analysis diagram of automatic assembly principle:

Due to my limited ability, if there are mistakes in the article, please point them out, and learn together.