Spring Boot Source Analysis-Start Principle

1. introduction

Spring Boot is a rapid development framework provided by Pivotal team. Spring MVC simplifies XML configuration by annotation + built-in Http server such as tomcat-embedded-core, integrates some commonly used third-party dependencies quickly (through Maven inheritance dependencies), and finally implements the implementation in the form of Java applications.

1.1 Convenient starter poms

Starter contains the dependencies needed to build a project to run quickly. It is a collection of dependency descriptors. When an application needs another spring service, it does not need to paste a large number of dependency descriptors. For example, to use redis in spring, you just need to include spring-boot-starter-redis dependencies in your project. All starters follow a similar naming pattern: spring-boot-starter-, which is a special type of application. This naming structure can help you find the starter you need. Many IDEs integrated Maven allow you to search dependencies by name.

1.2 demo

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

This is a simple implementation of SpringBoot's startup class, which will be expanded around in the next article.

Annotation Analysis of 2@SpringBoot Application

Here is the source implementation of the annotation @SpringBootApplication

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

It can be found that it is a combination of many annotations, the following specific analysis of the role played by each annotation here.

  • @ Target Target specifies an enumerated set of annotations that can be used through ElementType (FIELD/METHOD/PARAMETER...)
  • @ The Retention Retention annotation indicates that this type of annotation will be retained to that stage. There are three values:

    • RetentionPolicy.SOURCE - This type of Annotations is reserved only at the source level and is ignored at compile time
    • RetentionPolicy.CLASS -- This type of Annotations is retained when compiled and exists in the class file, but JVM will ignore it
    • RetentionPolicy.RUNTIME - This type of Annotations will be retained by JVM, so they can be run by JVM or other Enablers
  • @ Documented annotations indicate that this annotation should be recorded by the Javadoc tool. By default, Javadoc does not include annotations. But if @Documented is specified when annotations are declared, it will be processed by tools such as javadoc, so annotation type information will also be included in the generated document.
  • @ Inherited allows subclasses to inherit annotations from parent classes, which are only useful for class annotations and are invalid for methods and attributes.
  • @ SpringBootConfiguration annotations actually have the same function as @Configuration, and classes equipped with the annotations can complete some configurations in JavaConfig mode, and can no longer use XML configurations.
  • @ ComponentScan annotation completes the function of automatic scanning, which is equivalent to <context: component-scan> in Spring XML configuration file. It can use the basePackages attribute to specify the package to be scanned and the conditions for scanning. If not set, the Default scan @ComponentScan annotations in the same class and all classes in the same directory, so our Spring Book project will generally put the entry class in the top directory, so that we can ensure that all classes in the source directory can be scanned.
  • @ Enable AutoConfiguration is a key annotation that makes the configuration of Spring Boot so simplified. I've brought up the implementation of Enable AutoConfiguration. Let's appreciate it!

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    • @ AutoConfiguration Package annotations are used to save autoconfiguration classes for later use, such as JPA entity scanners, to scan entity classes defined by developers through annotations @Entity. In general, registration bean s are defined in containers.
    • @ Import (AutoConfiguration Import Selector. class) is the most critical part of the Enable AutoConfiguration annotation. With the help of AutoConfiguration Import Selector, it can help SpringBook applications load all eligible @Configuration configurations into the IoC container created and used by the current SpringBook. There's more to say about the @Import annotation. Talk about it another day.

On the topic of annotations, let's start with the code link below.

3 profiling code

Looking at the source code of Spring Application, you can see that the start of Spring Application consists of two parts:

  • New Spring Application (primarySources): Create Spring Application objects
  • run(args): Call the run method

3.1 Instantiating Spring Application Objects

The source code is as follows:

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;//1. Initialize resource loader
        Assert.notNull(primarySources, "PrimarySources must not be null");//2. Asserting that the resource loading class cannot be null
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//3. Initialize loading resource class set and de-duplicate
        this.webApplicationType = deduceWebApplicationType();//4. Inference whether the application type is Standard or Web
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));//5. Setting up application context initializer
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//6. Setting up listeners 
        this.mainApplicationClass = deduceMainApplicationClass();//7. Inference Application Entry Class
    }

Next, we will make a detailed analysis of the important implementations in the source code.

3.1.1 Initialization of Resource Loader

ResourceLoader interface, which is used to load resources in Spring, through which a Resouce object can be obtained. Friends who use spring know that it loads resources in many ways. Here are two commonly used interfaces and implementation classes that inherit ResourceLoader.

  • DefaultResourceLoader: As a direct implementation class of ResourceLoader interface, this class implements the basic resource loading function and can load a single resource.
  • ResourcePatternResolver: This interface inherits ResourceLoader and defines a method to load multiple resources, which can be used to load multiple resources.
1,DefaultResourceLoader

As mentioned above, this class implements the function of loading a single resource by implementing the ResourceLoader interface. Its subclasses implement specific resource access policies by inheriting it. Let's explore how this class loads a single resource:

    public Resource getResource(String location) {//Here are three ways to identify location s to load resources.
        Assert.notNull(location, "Location must not be null");
        //1. See if there is a custom Proocol Resolver, and if there is one, parse the location to get the Resource according to the custom Proocol Resolver.
        for (ProtocolResolver protocolResolver : this.protocolResolvers) {
            Resource resource = protocolResolver.resolve(location, this);
            if (resource != null) {
                return resource;
            }
        }
        //2. ClassPathResource is parsed according to whether the path matches "/" or "classpath:"
        if (location.startsWith("/")) {
            return getResourceByPath(location);
        }else if (location.startsWith(CLASSPATH_URL_PREFIX)) {//classpath
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
        }else {
            try {
                //The default incoming location is a URL path loaded to a UrlResource
                URL url = new URL(location);
                return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
            }
            catch (MalformedURLException ex) {
                // If none of the above three cases is satisfied, it will be handled according to "/".
                return getResourceByPath(location);
            }
        }
    }

Literacy: ProtocolResolver is a custom extension class for parsing location, with which we can randomly pass in different formats of location, and then parse and get our Resource according to the corresponding format.
Extension: During Spring container initialization, we can customize a class to implement the ProtocolResolver interface, and then implement the resolve method to parse specific location s to get Resoure.

2,ResourcePatternResolver

This interface inherits the ResourceLoader interface and adds the function of accessing multiple resources at the same time.

public interface ResourcePatternResolver extends ResourceLoader {
    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    // For example, using ant-style paths to match multiple resources under paths
    Resource[] getResources(String locationPattern) throws IOException;
}

PathMatching ResourcePatternResolver is a direct implementation class of the ResourcePatternResolver interface. It is based on pattern matching. By default, AntPathMatcher is used for path matching. In addition to supporting prefixes supported by ResourceLoader, PathMatching Resolver also supports "classpath*". Let's look at the source code to see how it achieves path*. Access to multiple resources.

    public Resource[] getResources(String locationPattern) throws IOException {
        Assert.notNull(locationPattern, "Location pattern must not be null");
         //First, determine whether the resource path is a resource under the class path (starting with "classpath*:").
        if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
            // Get PathMatcher through the getPathMatcher method. By default, only AntPathMatcher has an implementation class.
           // The isPattern s method is used to determine whether a path allows multiple matching resources (paths contain "*" or "?").
            if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
                //Find all resources for matching paths (ant style)
                return findPathMatchingResources(locationPattern);
            }
            else {
                //Find by class loader
                return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
            }
        }
        else {
            int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
                    locationPattern.indexOf(':') + 1);
            // Determine whether the following part of the resource path':'contains'*' or'?'
            if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
                // a file pattern
                return findPathMatchingResources(locationPattern);
            }
            else {
                // If there is no representation of a single resource, it is obtained by the ResourceLoader passed in from the constructor
                return new Resource[] {getResourceLoader().getResource(locationPattern)};
            }
        }
    }

Extension: Looking at the source code, we find that the Application Context interface also inherits the ResourcePatternResolver interface, indicating that it also integrates access to single or multiple resources.

  • When Spring needs access to resources, it does not actually need to directly use the Resource implementation class, but calls the getResource method to obtain resources.
  • When a Resource instance is retrieved from an Application Context instance, it will be responsible for selecting the specific implementation class of the Resource. The code is as follows:
    Resource res = ctx.getResource("some/resource/path/myTemplate.txt);

Spring uses the same strategy as Application Context to access resources. In other words:

  • If the Application Context is FileSystem Xml Application Context, res is the FileSystem Resource instance.
  • If the Application Context is a ClassPathXml Application Context, res is an instance of ClassPathResource.
  • If the Application Context is Xml Web Application Context, res is an instance of ServletContextResource.

That is to say, the Application Context will determine the specific resource access strategy, thus separating the application from the specific resource access strategy, which reflects the advantages of the policy model.

3.1.2 Set Application Context Initializers

  • Introduction: initializers is an instance attribute in Spring Application: List < Application Context Initializer <?> initializers. Each initailizer is an instance that implements the Application Context Initializer interface. Application Context Initializer is an interface provided in the Spring IOC container with the following source code:
    public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext>{
        void initialize(C applicationContext);
    }
  • Function: The function of the ApplicationContextInitializer interface is to do some initialization work during spring prepareContext. When the prepareContext method is executed during spring initialization, it calls back all the implementations of the ApplicationContextInitializer interface through the application Initializers method. So the setInitializers method is executed in the Spring Application construction method, which loads all the initialized ApplicationContextInitializer implementation classes into the set inside Spring Application.
  • Implementation: These initializers are Spring Boot s that get configuration initialization classes from the local META-INF/spring.factories file and the MITA-INF/spring.factories file in the jar file (note that all configuration classes of the configuration file are obtained here), and then through loadSpring Factories (classLoader). ToryClassName, Collections. emptyList ());

} Methods Get the full names of all implementation classes of the ApplicationContextInitializer interface, and finally get the application ContextInitializer implementation classes through the reflection mechanism.

  • Use: Through getSpring Factories Instances(

Application ContextInitializer. class) method to obtain implementation class

3.1.3 Set Listeners

The listeners member variable is a collection of ApplicationListener <?> type objects. You can see that the content of the member variable is retrieved using the same method as the member variable initializers, except that the incoming type changes from ApplicationContextInitializer.class to ApplicationListener.class.

    public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
        void onApplicationEvent(E event);
    }

This interface is based on the EventListener interface in JDK and practices the observer mode. For the observer pattern implementation of the Spring framework, it defines that the event type of interest needs to be a subclass of the Application Event type, which is also inherited from the EventObject class in the JDK.

3.1.4 Inference Application Entry Class

This method constructs a runtime exception and gets the name of the class in which main() resides by the stack frame of the method named main in the exception stack.

    private Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        }
        catch (ClassNotFoundException ex) {
            // Swallow and continue
        }
        return null;
    }

3.2 run method

The source code is as follows:

public ConfigurableApplicationContext run(String... args) {
    //1. Timing Monitoring Class
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    
    // 2. Initialization of application context and exception reporting set
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    
    // 3. Set the value of the system property java.awt.headless with the default value of: true (no graphical interface)
    configureHeadlessProperty();
    
    // 4. Create all Spring run listeners and issue start-up events
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
        // 5. Initialize default application parameter class
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
                
        // 6. Preparing Spring environment according to Spring Application RunListeners and application parameters
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
        configureIgnoreBeanInfo(environment);
        
        // 7. Preparing Banner Printer - ASCII Art Font Printed on console when Spring Boot is started
        Banner printedBanner = printBanner(environment);
        
        // 8. Creating Spring Context
        context = createApplicationContext();
        
        // 9. Preparing exception reports
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
                
        // 10. Spring context preprocessing
        prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
                
        // 11. Refresh Spring Context
        refreshContext(context);
        
        // 12. Spring context postprocessing
        afterRefresh(context, applicationArguments);
        
        // 13. Stop Timing Monitoring Class
        stopWatch.stop();
        
        // 14. Output Log Records Execution Main Class Name, Time Information
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
        }
        
        // 15. Publish application context start-up completion events
        listeners.started(context);
        
        // 16. Execute all Runner runners
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
 
    try {
        // 17. Publish application context ready events
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    // 18. Return to the application context
    return context;
}

Following are some important steps mentioned in the run method:

3.2.1 Timing Monitoring Class

The start-up method is as follows:

    public void start() throws IllegalStateException {
        start("");
    }
    
    public void start(String taskName) throws IllegalStateException {
        if (this.currentTaskName != null) {
            throw new IllegalStateException("Can't start StopWatch: it's already running");
        }
        this.currentTaskName = taskName;
        this.startTimeMillis = System.currentTimeMillis();
    }

You can see that it passes in an empty string to the current task as the task name, and then records the start time of the current Spring Book application. And it will determine whether the current task name exists to ensure that Spring Book applications do not start repeatedly.

3.2.2 Initialize application context and exception reporting set

Here, we only initialize an application context object context and an empty exception reporting set. For specific purposes, see below.

3.2.3 Setting System Properties

The configureHeadless Property method is implemented as follows:

    private void configureHeadlessProperty() {
        System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
                SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
    }
    private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";

This method sets a system property named java.awt.headless. Looking at its source code, it can be found that it sets the value of System.setProperty(), whose value comes from System.getProperty(), which is not surprising, because getProperty() in System has two overloading methods, getProperty() has two methods, one is single parameter and the other is double parameter. It uses a two-parameter method, which returns a default value specified by the caller when it is not available, so it is fetched here and set later. The purpose of this setting is to ensure that the program starts even if no monitor is detected (the server does not need the monitor).

3.2.4 Create all Spring run listeners and issue start-up events

The realization is as follows:

//Get all Spring Application RunListeners listeners from args
SpringApplicationRunListeners listeners = getRunListeners(args);

//You should be familiar with this code to get the Spring Application RunListeners extension
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

Class <?>[] types = new Class <?> []{Spring Application. class, String []. class}; type loads the corresponding listener and creates a Spring Application RunListener instance

The following is the same as the previous process of instantiating initializers. Get a list of instance class names related to Spring Application RunListener. class from spring.factories through the getSpringFactories Instances method.

3.2.5 Initialization of default application parameter classes

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

args is a command-line parameter to start Spring applications, which can be accessed in Spring applications.
For example: - server.port=9000

3.2.6 Prepare the Spring environment based on the running listener and application parameters

Create and configure the environment to be used by the current SpringBook application (including configuring the PropertySource and Profile to be used (its function is to specify the active configuration file to load different configurations) and traverse the environment Prepared () method that invokes all SpringApplication RunListeners. Environment is ready.
The source code is as follows:

    private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        //Get or create an environment (returns directly when there is one, and does not create a return)
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        //Configuration environment: Configure Property Sources and Active Profiles
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        //listeners environment preparation (that is, broadcasting Application Environment Prepared Event events).
        listeners.environmentPrepared(environment);
        //Binding the environment to Spring Application
        bindToSpringApplication(environment);
        //Converting an environment to a Standard Environment if it is not a web environment
        if (this.webApplicationType == WebApplicationType.NONE) {
            environment = new EnvironmentConverter(getClassLoader())
                    .convertToStandardEnvironmentIfNecessary(environment);
        }
        //Configure the recursive dependency of Property Sources on itself
        ConfigurationPropertySources.attach(environment);
        return environment;
    }

Role of prepareEnvironment: Load external configuration resources to environment, including command line parameters, servletConfigInitParams, servletContextInitParams, system properties, sytemEnvironment, random, application.yml(.yaml/.xml/.properties), and initialize the logging system.

3.2.7 Prepare Banner Printer

This function is only for self-entertainment, not too much interpretation, look at the source code is.

    private Banner printBanner(ConfigurableEnvironment environment) {
        if (this.bannerMode == Banner.Mode.OFF) {
            return null;
        }
        ResourceLoader resourceLoader = (this.resourceLoader != null ? this.resourceLoader
                : new DefaultResourceLoader(getClassLoader()));
        SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
                resourceLoader, this.banner);
        if (this.bannerMode == Mode.LOG) {
            return bannerPrinter.print(environment, this.mainApplicationClass, logger);
        }
        return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
    }

3.2.8 Create Spring Context

The source code is as follows:

public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context.annotation.AnnotationConfigApplicationContext";

protected ConfigurableApplicationContext createApplicationContext() {
        // First determine if there is a specified implementation class
        Class<?> contextClass = this.applicationContextClass;
        // If not, select according to the application type
        if (contextClass == null) {
            try {
                //Create a concrete instance of the Configurable Application Context based on the type of web Application Type to reflect.
                switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, "
                                + "please specify an ApplicationContextClass",
                        ex);
            }
        }
        // Obtaining instances of corresponding classes by reflection
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

createApplicationContext() is a simple method with two branches:

  • Customize the implementation class of ApplicationContext
  • Matching the corresponding Application Context according to the current application type, web Application Type, is a servlet, reaction or non-Web application.

3.2.9 Prepare exception reports

The logic of this step, like the instantiation initializer and the listener, is to get the name of the configured exception class and instantiate all exception handling classes by calling the getSpringFactories Instances method.

3.2.10 Spring context preprocessing

The source code is as follows:

    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        //Setting up container environments, including variables
        context.setEnvironment(environment);
 
        //Setting the context of the bean generator and resource loader
        postProcessApplicationContext(context);
 
        //Application Context Initializer in the execution container (including spring.factories and custom instances)
        applyInitializers(context);
 
        //The contextPrepared event method that triggers all Spring Application RunListener listeners
        listeners.contextPrepared(context);
 
        //Record startup log
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
 
        // Add boot-specific singleton bean s
context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }
        // Load all resources
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        //Load our startup class and inject the startup class into the container
        load(context, sources.toArray(new Object[0]));
 
        //The contextLoaded event method that triggers all Spring Application RunListener listeners
        listeners.contextLoaded(context);
    }

This block preprocesses the entire context, such as triggering the response event of the listener, loading resources, setting up the context environment, and so on.

3.2.11 Refresh Spring Context

The source code is as follows:

    private void refreshContext(ConfigurableApplicationContext context) {
        refresh(context);
        if (this.registerShutdownHook) {
            try {
                //Register a shutdown hook to the JVM runtime to close this context when the JVM shuts down
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
    }

This piece mainly does two things:

  1. Initialization of the entire IoC container by refresh method (including location, parsing, registration of Bean resources, etc.)
  2. Register a shutdown hook to the JVM runtime and close the context when the JVM shuts down, unless it has been shut down at that time.)

3.2.12 Spring context postprocessing

protected void afterRefresh(ConfigurableApplicationContext context,
        ApplicationArguments args) {
}

This method has not been implemented, so we can do some customized operations according to our needs.

3.2.13 Stop Timing Monitoring Class

The source code is as follows:

    public void stop() throws IllegalStateException {
        if (this.currentTaskName == null) {
            throw new IllegalStateException("Can't stop StopWatch: it's not running");
        }
        long lastTime = System.currentTimeMillis() - this.startTimeMillis;
        this.totalTimeMillis += lastTime;
        this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
        if (this.keepTaskList) {
            this.taskList.add(this.lastTaskInfo);
        }
        ++this.taskCount;
        this.currentTaskName = null;
    }

This method is mainly to stop the operation of the timer listener and to count some task execution information.

3.2.14 Output Log Records Execution Main Class Name and Time Information

The source code is as follows:

if (this.logStartupInfo) {
    new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
}

Used to print main class information and time information.

3.2.15 Publish Application Context Launch Completion Events

The source code is as follows:

public void started(ConfigurableApplicationContext context) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.started(context);
    }
}

Execute the start method of all Spring Application RunListener implementations.

3.2.16 Execute all Runner runners

The Runner runner is used for some business initialization operations at service startup, which are performed only once after service startup.
Spring Boot provides two service interfaces, CommandLine Runner and Application Runner, for Application Runner and CommandLine Runner.
Contrast:

  • Same points

    • Both are executed after the service is started, and only once.
    • Both of them can get the command line parameters of the application.
    • Both are consistent in execution timing (customized execution priority can be achieved through Ordered-related interfaces or annotations.)
  • Difference

    • Although both are command-line parameters for the application, Application Runner retrieves the encapsulated Application Arguments object, while CommandLine retrieves the sourceArgs attribute (List < String >) in Application Arguments, which is the original parameter string list (command-line parameter list).

The source code is as follows:

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList<>();
// Get the Application Runner implementation class runners. addAll (context. getBeans OfType (Application Runner. class). values () from the Spring container;
// Get the CommandLineRunner implementation class runners. addAll (context. getBeans OfType (CommandLineRunner. class). values () from the Spring container;
        //sort
        AnnotationAwareOrderComparator.sort(runners);
        //Callback
        for (Object runner : new LinkedHashSet<>(runners)) {
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner, args);
            }
            if (runner instanceof CommandLineRunner) {
                callRunner((CommandLineRunner) runner, args);
            }
        }
    }

Application Runner or CommandLine Runner, which executes a business initialization code after the application is started, achieves similar results. Because the method parameter of Application Runner is Application Arguments object, it is more convenient to use, so it is more recommended to use.

3.2.17 Publish Application Context Ready Events

Source code is as follows

    public void running(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.running(context);
        }
    }

running event method that triggers all Spring Application RunListener listeners.

summary

SpirngBoot starts the process here, and the next article will analyze the specific scenarios of SpringBoot. I hope every friend who sees this article can get some benefit. At the same time, we welcome your valuable opinions to grow together.

Tags: Java Spring jvm xml

Posted on Wed, 11 Sep 2019 00:32:02 -0700 by AlexWD