Spring boot application in-depth learning

Keywords: Java Spring SpringBoot github less

This section mainly introduces the in-depth learning of spring boot application class related source code.

It mainly includes:

  1. Spring boot application custom boot configuration
  2. Spring boot application life cycle, as well as customized configuration in various stages of the life cycle.

This section uses springboot 2.1.10.release. The corresponding sample source code is: https://github.com/laolunsi/spring-boot-examples

SpringBoot application startup process:

SpringApplication application = new SpringApplication(DemoApplication.class);
application.run(args);

I. Application class custom startup configuration

After creating the SpringApplication object, before calling the run method, we can use the SpringApplication object to add some configurations, such as disabling banner, setting the application type, and setting the profile

Give an example:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(DemoApplication.class);
        // Set banner disable
        application.setBannerMode(Banner.Mode.OFF);
        // Enable application test file as profile
        application.setAdditionalProfiles("test");
        // Set the application type to NONE, i.e. close automatically after startup
        application.setWebApplicationType(WebApplicationType.NONE);
        application.run(args);
    }

}

You can also use the SpringApplicationBuilder class to create SpringApplication objects. The builder class provides an API for chain call, which is more convenient to call and enhances readability.

        new SpringApplicationBuilder(YqManageCenterApplication.class)
                .bannerMode(Banner.Mode.OFF)
                .profiles("test")
                .web(WebApplicationType.NONE)
                .run(args);

II. application life cycle

The life cycle of spring application mainly includes:

  1. Preparation stage: mainly including loading configuration, setting main bean source, inferring Application type (three kinds), creating and setting SpringBootInitializer, creating and setting Application listener, inferring main entry class
  2. Running stage: start time listening, load running listener, create Environment, print banner, create and load context, broadcast application started, broadcast application running

Let's first look at the source code analysis:

SpringBootApplication Builder:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        
        // Set default configuration
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();
        this.isCustomEnvironment = false;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        // Set main bean source
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        // Infer and set application types (three types)
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
          // Creating and setting up the SpringBootInitializer
  this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
          // Creating and setting up a SpringBoot listener
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        // Infer and set the main entry class
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

SpringApplication.run method source code:

public ConfigurableApplicationContext run(String... args) {
        // Enable time monitoring
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
    
        // Load the Spring application run listener
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            // Create environment (including PropertySources and Profiles)
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            
            // Print banner
            Banner printedBanner = this.printBanner(environment);
            
            // Create context (different application types correspond to different contexts)
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            // Load context (IOC container is also initialized)
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            // Call applicationContext.refresh
            this.refreshContext(context);
            // Empty method
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop(); // Turn off time listening; this will calculate the full start time
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            // Broadcast that the SpringBoot application has been started. All the started methods in the SpringBootApplicationRunListener will be called
            listeners.started(context);
            
            // Traverse all the implementation classes of ApplicationRunner and CommadnLineRunner, and execute their run methods
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            // When broadcasting a spring boot application running, all the running methods in the SpringBootApplicationRunListener will be called
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            // When an exception occurs in run, handle the exception; call the failed method in the listener reporting the error, broadcast the application failed to start, and spread the exception out
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

III. user defined configuration of application life cycle

In the life cycle of spring application, we can also add some custom configurations.

The following configuration is mainly implemented by implementing the interface provided by Spring, then creating a new META-INF/spring.factories file under resources, and adding this class in it.

In the preparation phase, you can add the following custom configurations:

3.1 implementation class of custom ApplicationContextInitializer

@Order(100)
public class MyInitializer implements ApplicationContextInitializer {

@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
    System.out.println("Custom application context initializer:" + configurableApplicationContext.toString());
}
}

Define another My2Initializer and set @ Order(101)

Then configure the following in the spring.factories file:

# initializers
org.springframework.context.ApplicationContextInitializer=\
  com.example.applicationdemo.MyInitializer,\
  com.example.applicationdemo.My2Initializer

Start project:

3.2 implementation class of custom ApplicationListener

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);
}![file](https://image-static.segmentfault.com/140/336/1403360350-5ddb5f8a5ab9d_articlex)

That is, the implementation class of the ApplicationListener interface listening to the ApplicationEvents class.

First, see how many kinds of ApplicationEvents are available:

It can also be split.

We set two applicationlisteners here to listen to ApplicationEnvironmentPreparedEvent

@Order(200)
public class MyApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {

    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent) {
        System.out.println("MyApplicationListener: Application environment ready" + applicationEnvironmentPreparedEvent.toString());
    }
}

Add the configuration of applicationListener in spring.factories:

# application-listeners
org.springframework.context.ApplicationListener=\
  com.example.applicationdemo.MyApplicationListener,\
  com.example.applicationdemo.MyApplicationListener2

In the startup phase, you can add the following custom configurations:

3.3 implementation class of custom SpringBootRunListener

Monitor the whole spring boot application life cycle

public interface SpringApplicationRunListener {
      // Application startup
    void starting();

    // The ConfigurableEnvironment is ready to be applied and can be adjusted at this time
    void environmentPrepared(ConfigurableEnvironment environment);

      // Context ready
    void contextPrepared(ConfigurableApplicationContext context);

      // Context load complete
    void contextLoaded(ConfigurableApplicationContext context);

      // Start up complete (Beans loaded into container)
    void started(ConfigurableApplicationContext context);

      // Application running
    void running(ConfigurableApplicationContext context);

      // App failed to run
    void failed(ConfigurableApplicationContext context, Throwable exception);
}

We can customize the implementation class of SpringApplicationRunListener and define our own listener by overriding the above methods.

For example:

public class MyRunListener implements SpringApplicationRunListener {

    // Note that this constructor should be added. Neither of the two parameters should be less. Otherwise, the startup will report an error. For details of the error, see the bottom of this class
    public MyRunListener(SpringApplication springApplication, String[] args) {

    }

    @Override
    public void starting() {
        System.out.println("MyRunListener: Program start");
    }

    // Other methods are omitted without modification
}

Then add this class in the spring.factories file:

org.springframework.boot.SpringApplicationRunListener=\
  com.example.applicationdemo.MyRunListener

Start up:

3.4 customize ApplicationRunner or CommandLineRunner

In the application run method, there is a line like this:

this.callRunners(context, applicationArguments);

After careful analysis of the source code, it is found that the function of this sentence is: during the startup of spring boot application, all application runners and commandlinerunners will be traversed to execute their run methods.

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);
            }
        }

    }
@FunctionalInterface
public interface CommandLineRunner {
    void run(String... args) throws Exception;
}
@FunctionalInterface
public interface ApplicationRunner {
    void run(ApplicationArguments args) throws Exception;
}

Define an implementation class and add @ Component. These two implementation classes do not need to be configured in spring.factories.

OK, about the specific use of these custom configurations, we will continue to introduce them later, please keep watching! Thank!

Please go to https://github.com/laolunsi/spring-boot-examples See.

Communication learning

Personal website: http://www.eknown.cn

GitHub: https://github.com/laolunsi

Public number: apes story, "sharing technology, and understanding life", welcome attention!

Posted by mapexdrum on Sun, 24 Nov 2019 21:07:19 -0800