Follow the wechat official account: CodingTechWork, learn and progress together.

The introduction

When using Spring Boot to set up a project and start the project, some requirements to start initialization data or resources are often encountered, such as loading certain configuration file content in advance, initializing certain information, and completing security certification. Here’s a summary of several ways to initialize data.

@bean annotation configuration

use

Write a Configuration class and initialize it using @Configuration and @Bean annotations.

Use the sample

package com.example.andya.demo.conf;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/ * * *@author Andya
 * @createThe 2020-09-14 21:37 * /
@Configuration
public class InitConfigTest {

    @Value("${key}")
    private String key;

    @Bean
    public String testInit(a){
        System.out.println("init key: " + key);
        returnkey; }}Copy the code

ApplicationRunner interface

use

Write classes that implement the ApplicationRunner interface and implement the run() method before the project starts the springApplication.run (xxxApplication.class, args) method of the class’s XXXApplication. @Componet completes execution after all Spring Beans are initialized.

Use the sample

package com.example.andya.demo.service.initTest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

/ * * *@author Andya
 * @dateThe 2020-09-14 21:37 * /
@Component
public class ApplicationRunnerTest implements ApplicationRunner {

    @Value("${key}")
    private String key;

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        System.out.println("ApplicationRunner test: init key : "+ key); }}Copy the code

CommandLineRunner interface

use

Similar to the ApplicationRunner interface, we also write classes that implement the CommandLineRunner interface, implement the Run () method, This method is executed before the project starts the springApplication.run (xxxApplication.class, args) method of the class’s XXXApplication, and @Componet after all Spring Beans are initialized. When multiple classes implement interfaces, the Order can be controlled by the @order annotation. The smaller the @order (n), the earlier the execution starts.

Use the sample

Example 1

package com.example.andya.demo.service.initTest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/ * * *@author Andya
 * @createThe 2020-09-14 21:37 * /
@Component
@Order(1)
public class CommandLineRunner1Test implements CommandLineRunner {

    @Value("${key}")
    private String key;

    @Override
    public void run(String... strings) throws Exception {
        System.out.println("CommandLineRunner first init: 1)init key : "+ key); }}Copy the code

Example 2

package com.example.andya.demo.service.initTest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/ * * *@author Andya
 * @createThe 2020-09-14 21:37 * /
@Component
@Order(2)
public class CommandLineRunner2Test implements CommandLineRunner {

    @Value("${key}")
    private String key;

    @Override
    public void run(String... strings) throws Exception {
        System.out.println("CommandLineRunner second init: 2)init key : "+ key); }}Copy the code

Two kinds of interface analysis

Interface contrast

CommandLineRunner and ApplicationRunner are both interfaces with different internal parameters. The CommandLineRunner parameter is a primitive parameter of type String, which is not processed. The latter is type ApplicationArguments that encapsulates the original arguments.

The execution result

Examples of the results of the above three methods

____ ____ _ /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \ / _ ` | \ \ \ \ \ \ / ___) | | _) | | | | | | | (_ | |))))' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.5.6. RELEASE) the 2020-09-14 21:45:28. 403 INFO 25408 - [the main] com. Example. Andya. Demo. DemoApplication: Starting DemoApplication on DESKTOP-KC40970 with PID 25408 (F:\selfcode\target\classes started by Hugh in F:\selfcode) The 2020-09-14 21:45:28. 25408-406 the INFO [main] com. Example. Andya. Demo. DemoApplication: No active profile set, falling back to default profiles: Default 21:45:28 2020-09-14. 25408-434 the INFO [main] ationConfigEmbeddedWebApplicationContext: Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1542153: startup date [Tue Sep 15 11:28:28 CST 2020]; The root of the context hierarchy 21:45:29 2020-09-14. 25408-322 the INFO [main] S.B.C.E.T.T omcatEmbeddedServletContainer: Tomcat initialized with port(s): 9000 (HTTP) 21:45:29 2020-09-14. 25408-327 the INFO [main] o.a pache, catalina. Core. StandardService: Starting the service [Tomcat] 2020-09-14 21:45:29. 327 INFO 25408 - [the main] org. Apache. Catalina. Core. StandardEngine: Starting Servlet Engine: Apache Tomcat/8.5.16 2020-09-14 21:45:29.385 INFO 25408 -- [ost-startStop-1] O.A.C.C.C. [Tomcat].[/] : Apache Tomcat/8.5.16 2020-09-14 21:45:29.385 INFO 25408 -- [ost-startStop-1] O.A.C.C.C. Initializing Spring Embedded WebApplicationContext 2020-09-14 21:45:29.385 INFO 25408 -- [Ost-startstop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: Initialization Completed in 953 MS 2020-09-14 21:45:29.504 INFO 25408 -- [Ost-startstop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet'to [/] 2020-09-14 21:45:29. 506 INFO - 25408 [ost startStop - 1] O.S.B.W.S ervlet. FilterRegistrationBean: Mapping filter: 'characterEncodingFilter'to: [/ *] 21:45:29 2020-09-14. 25408-506 the INFO] [ost - startStop - 1 O.S.B.W.S ervlet. FilterRegistrationBean: Mapping filter: 'hiddenHttpMethodFilter'to: [/ *] 21:45:29 2020-09-14. 25408-506 the INFO] [ost - startStop - 1 O.S.B.W.S ervlet. FilterRegistrationBean: Mapping filter: 'httpPutFormContentFilter'to: [/ *] 21:45:29 2020-09-14. 25408-506 the INFO] [ost - startStop - 1 O.S.B.W.S ervlet. FilterRegistrationBean: Mapping filter: 'requestContextFilter', [/ *] init key: value 21:45:29 2020-09-14. 25408-818 the INFO [main] S.W.S.M.M.A.R equestMappingHandlerAdapter: Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1542153: startup date [Tue Sep 15 11:28:28 CST 2020]; The root of the context hierarchy 21:45:29 2020-09-14. 25408-857 the INFO [main] S.W.S.M.M.A.R equestMappingHandlerMapping: Mapped "{[/aopTest/sayHi/{name}],methods=[GET]}" onto public java.lang.String Com. Example. Andya. Demo. Controller. AopController. SayHi (Java. Lang. String) 21:45:29 2020-09-14. 25408-857 the INFO [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/hello],methods=[GET]}" onto public java.lang.String com.example.andya.demo.controller.HelloController.hello() The 2020-09-14 21:45:29. 25408-859 the INFO [the main] S.W.S.M.M.A.R equestMappingHandlerMapping: Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity
      
       > org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2020-09-14 21:45:29. 25408-859 the INFO [main] S.W.S.M.M.A.R equestMappingHandlerMapping: Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.se Rvlet. HTTP. 21:45:29 HttpServletResponse) 2020-09-14. 25408-923 the INFO [main] O.S.W.S.H andler. SimpleUrlHandlerMapping:  Mapped URL path [/webjars/**] onto handler of type [class Org. Springframework. Web. Servlet. Resource. 21:45:29 ResourceHttpRequestHandler] 2020-09-14. 25408-923 the INFO [main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] The 2020-09-14 21:45:29. 25408-955 the INFO [main] O.S.W.S.H andler. SimpleUrlHandlerMapping: Mapped URL path [/**/favicon.ico] onto handler of type [class Org. Springframework. Web. Servlet. Resource. 21:45:30 ResourceHttpRequestHandler] 2020-09-14. 25408-064 the INFO [main] o.s.j.e.a.AnnotationMBeanExporter : Registering Beans for JMX Exposure on startup 2020-09-14 21:45:30.069 INFO 25408 -- [main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing 21:45:30 2020-09-14. 25408-095 the INFO [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 9000 (http) CommandLineRunner first init: 1)init key : value CommandLineRunner second init: 2)init key : value ApplicationRunner test: init key : Value the 2020-09-14 21:45:30. 097 INFO 25408 - [the main] com. Example. Andya. Demo. DemoApplication: Started DemoApplication in 1.911 seconds (JVM running for 2.601) 2020-09-14 21:46:00.004 INFO 25408 -- [pool-1-thread-1] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named '
      taskExecutor'Either 2020-09-14 21:46:59.781 INFO 25408 -- [NIO-9000-exec-1] O.A.C.C.C. [Tomcat].[/] :' either 2020-09-14 21:46:59.781 INFO 25408 -- [NIO-9000-EXEC-1] O.A.C.C.C. [Tomcat].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'25408-2020-09-14 21:46:59. 781 INFO [nio - 9000 - exec - 1] O.S.W eb. Servlet. The DispatcherServlet: FrameworkServlet'dispatcherServlet': initialization started the 2020-09-14 21:46:59. 802 INFO - 25408 [nio - 9000 - exec - 1] O.S.W eb. Servlet. The DispatcherServlet: FrameworkServlet 'dispatcherServlet': initialization completed in 21 ms
Copy the code

Source code analysis

XxxApplication start class

package com.example.andya.demo;

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

In the project, click SpringApplication.run(demoApplication.class, args); The run method for source tracing.

SpringApplication class source

	// constructor 1
    public SpringApplication(Object... sources) {
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();
        this.initialize(sources);
    }
	// constructor 2
    public SpringApplication(ResourceLoader resourceLoader, Object... sources) {
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();
        this.resourceLoader = resourceLoader;
        this.initialize(sources);
    }

	/ / initialize method
    private void initialize(Object[] sources) {
    	// Save the configuration class if source is not empty
        if(sources ! =null && sources.length > 0) {
            this.sources.addAll(Arrays.asList(sources));
        }
		// Check whether the application is a Web application
        this.webEnvironment = this.deduceWebEnvironment();
        / / to get and keep container initialization ApplicationContextInitializer class, through SpringFactoriesLoader. LoadFactoryNames method
        / / from the meta-inf/spring. Factories path to obtain ApplicationContextInitializer collection
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
		/ / to get and save the listener ApplicationListener class, also, by SpringFactoriesLoader. LoadFactoryNames method
		// Get the ApplicationListener collection from the meta-INF/spring.Factories path
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        // Get the class containing the main method by tracing the stack to the method named main
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }
    
    1 / / the run () method
    public static ConfigurableApplicationContext run(Object source, String... args) {
        return run(new Object[]{source}, args);
    }
	2 / / the run () method
    public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
        return (new SpringApplication(sources)).run(args);
    }
    // Run () method 3, bottom level
    public ConfigurableApplicationContext run(String... args) {
    	// Create a new timing tool class StopWatch
        StopWatch stopWatch = new StopWatch();
        // Start the timer utility class StopWatch
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        // Set the system properties of java.awt.headless, if the server does not need a display
        this.configureHeadlessProperty();
        / / get the listener SpringApplicationRunListeners, calls the getSpringFactoriesInstances () method
        / / this method is called again loadFactoryNames () method from the meta-inf/spring. The factories get SpringApplicationRunListeners set path
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        // Start the listener
        listeners.starting();

        try {
        	// Wrap args arguments into ApplicationArguments
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            / / prepared environment: internal call the enclosing configureEnvironment () and listeners environmentPrepared () method
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            // Print the Banner from the environment. You can customize the Banner
            Banner printedBanner = this.printBanner(environment);
            // Create a container for Spring
            context = this.createApplicationContext();
            // Analyze and diagnose whether there is a problem with the project startup
            new FailureAnalyzers(context);
            // Prepare the container context:
            //1) Set the container environment: context.setenvironment (environment);
            / / 2) setting beanNameGenerator and resourceLoader: enclosing postProcessApplicationContext (context);
            //3) Initialize the context and check whether it accepts containers of this type: this.applyInitializers(context);
            / / 4) trigger monitor events: listeners. ContextPrepared (context); Is an empty function;
            / / 5) registered bean: through the context. GetBeanFactory () registerSingleton injection springApplicationArguments and springBootBanner () method to the container
            //6) getSources: Set sources = this.getsources ();
            This.load (context, sources.toarray (new Object[sources.size()]));
            // Set beanNameGenerator, resourceLoader and Environment for loader
            // Then call the load() method to load the class, resource, package, and charSequence of different source types.
            // listeners. ContextLoaded (context); for
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            // Refresh the Spring container
            this.refreshContext(context);
            // Get all applicationRunners and CommandLineRunner from the container to call callRunner
            this.afterRefresh(context, applicationArguments);
            / / trigger event monitoring, all SpringApplicationRunListener callFinishedListener callback
            listeners.finished(context, (Throwable)null);
            // The timer stops
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
			// The Ioc container context is returned after the SpringBoot project is started
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
            throw newIllegalStateException(var9); }}protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
        this.callRunners(context, args);
    }
    //callRunners
    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList();
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        AnnotationAwareOrderComparator.sort(runners);
        Iterator var4 = (new LinkedHashSet(runners)).iterator();

        while(var4.hasNext()) {
            Object runner = var4.next();
            if (runner instanceof ApplicationRunner) {
                this.callRunner((ApplicationRunner)runner, args);
            }

            if (runner instanceof CommandLineRunner) {
                this.callRunner((CommandLineRunner)runner, args); }}}Copy the code

In the source code above, we examined a process that SpringBoot initiates, where ApplicationRunner and CommandLineRunner are executed in callRunners methods, as seen in the source code’s run() method, click-by-click tracing.

Reference jdk1.8