编程知识 cdmana.com

Implementation principle of springboot

The most common SpringBoot Application startup class

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

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

springboot application , Just configure @SpringBootAplication annotation , It will start automatically , Why? ?

We go into this annotation and we can see @SpringBootAplication It's a combination annotation, The most important annotation yes @SpringBootConfiguration,@EnableAutoConfiguration and @ComponentScan. 

@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 {}

@SpringBootConfiguration It's essentially a @Configuration. The startup class is marked with @SpringBootConfiguration after , In fact, it is also a IOC Configuration class of container .

@ComponentScan Annotation is the automatic scanning function , amount to Spring XML In the configuration file :<context:component-scan>, have access to encludeFilters,includeFilters Specifies or excludes packages to be scanned , And the conditions of scanning . And finally put these bean The definition is loaded into the container .

@EnableAutoConfiguration It's Jean Spring Boot The configuration of the key annotations can be so simplified ,Spring-Boot According to the statement of the application jar Package dependence on Spring The framework is automatically configured . For example, according to spring-boot-starter-web , To determine if your project needs to add webmvc and tomcat, It will automatically help you configure web Default configuration required in the project .


@EnableAutoConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
// Class imported EnableAutoConfigurationImportSelector
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

class EnableAutoConfigurationImportSelector It's a ImportSelector Implementation class of interface , and ImportSelector Interface selectImports The class returned by the method will be Spring Container management .

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
   
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            try {
                // load META-INF/spring-autoconfigure-metadata.properties file 
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                // Get the attribute and value of the annotation 
                AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                // stay classpath All of them META-INF/spring.factories Find in the file org.springframework.boot.autoconfigure.EnableAutoConfiguration Value , And encapsulate it into a List Back in 
                List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                // For the last step back List De duplication of elements in 、 Sort 
                configurations = this.removeDuplicates(configurations);
                configurations = this.sort(configurations, autoConfigurationMetadata);
                // On the basis of the first 2 The attribute values obtained in step exclude some specific classes 
                Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                this.checkExcludedClasses(configurations, exclusions);
                configurations.removeAll(exclusions);
                // What you got in the last step List To filter , The basis of filtering is conditional matching . The filter used here is org.springframework.boot.autoconfigure.condition.OnClassCondition The final return is a ConditionOutcome[] Array .
                configurations = this.filter(configurations, autoConfigurationMetadata);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return (String[])configurations.toArray(new String[configurations.size()]);
            } catch (IOException var6) {
                throw new IllegalStateException(var6);
            }
        }
    }
}

So this annotation @EnableAutoConfiguration How does formula work ?

In the main startup class main Function , Would call SpringApplication.run(DemoApplication.class,args), And then it's done in two steps , The first step is to create SpringApplication object , The second step is to run run Method .

First step 、 establish SpringApplication object

The main function initialization of this step SpringApplication object , Find... From the classpath META-INF/spring.factories All configured ApplicationContextInitializer and ApplicationListener, And save it , In order to call , Finally find main Method's main configuration class .

private void initialize(Object[] sources) {
    // Save the main configuration class 
    if (sources != null && sources.length > 0) {
        this.sources.addAll(Arrays.asList(sources));
    } 
    // Judge whether there is a web application 
    this.webEnvironment = deduceWebEnvironment();
    // Find... From the classpath META‐INF/spring.factories All configured ApplicationContextInitializer; Then save          rise 
 Come on 
    setInitializers((Collection) getSpringFactoriesInstances(
    ApplicationContextInitializer.class));
    // Find... From the classpath ETA‐INF/spring.factories All configured ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // Found in multiple configuration classes main Method's main configuration class 
    this.mainApplicationClass = deduceMainApplicationClass();
}

The second step 、 function run Method

run The important point in the method is to create IOc Containers context = createApplicationContext();, Finally, it returns to the activated IOC Containers . In the middle refreshContent(), Finally called spring Container of refresh when ,invokeBeanFactoryPostProcessors(beanFactory) Method is called ConfigurationClassPostProcessor.ConfigurationClassPostProcessor Will resolve to our main class , hold @Import Take out the class in , Call it the selectImports() Method . then spring The container will respond to selectInports Method to return the configuration class for processing .

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    FailureAnalyzers analyzers = null;
    configureHeadlessProperty();
    // obtain SpringApplicationRunListeners; From the classpath META‐INF/spring.factories
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // Callback all fetches SpringApplicationRunListener.starting() Method 
    listeners.starting();
    try {
        // Encapsulate command line arguments 
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
    args);
        // Prepare the environment 
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
    applicationArguments);
        // Callback... When the environment is created SpringApplicationRunListener.environmentPrepared(); Environment standard 
     Prepare for completion 
        Banner printedBanner = printBanner(environment);
        // establish ApplicationContext; Decide to create web Of ioc Or ordinary ioc
        context = createApplicationContext();
        analyzers = new FailureAnalyzers(context);
        // Prepare the context ; take environment Save to ioc in ; and applyInitializers();
        //applyInitializers(): Recall all of the previously saved ApplicationContextInitializer Of initialize Method 
        // Call back all SpringApplicationRunListener Of contextPrepared();
        //
        prepareContext(context, environment, listeners, applicationArguments,
    printedBanner);
        //prepareContext Call back all the SpringApplicationRunListener Of contextLoaded();
        //s Refresh the container ;ioc Container initialization ( If it is web Applications will also create embedded Tomcat);Spring Annotated edition 
        // scanning , establish , Where to load all components ;( Configuration class , Components , Automatic configuration )
        refreshContext(context);
        // from ioc Get all the ApplicationRunner and CommandLineRunner Make a callback 
        //ApplicationRunner Call back first ,CommandLineRunner Callback again 
        afterRefresh(context, applicationArguments);
        // be-all SpringApplicationRunListener Callback finished Method 
        listeners.finished(context, null);
        stopWatch.stop();
        if (this.logStartupInfo) {
        new StartupInfoLogger(this.mainApplicationClass)
        .logStarted(getApplicationLog(), stopWatch);
        }
        // Whole SpringBoot After the application is started, it will return to the started ioc Containers ;
        return context;
    } catch (Throwable ex) {
        handleRunFailure(context, listeners, analyzers, ex);
        throw new IllegalStateException(ex);
    }
}

 

版权声明
本文为[Wooden pine cat]所创,转载请带上原文链接,感谢

Scroll to Top