Several ways to initialize resources in Spring Boot

Suppose there is a requirement to complete the initialization of thread pool, encryption certificate loading and other functions during project startup, what would you do? If you don't have a good answer, please look down. Today, I will introduce several ways to initialize resources in Spring Boot to help you solve and answer this question.

CommandLineRunner

  • Define the initialization class MyCommandLineRunner

  • Implement the CommandLineRunner interface and its run() method, in which the initialization logic is written

  • Register as Bean and add @ Component annotation

  • The sample code is as follows:

 @Component
 public class MyCommandLineRunner implements CommandLineRunner {
     
 	@Override
 	public void run(String... args) throws Exception {
 		System.out.println("... init resources by implements CommandLineRunner");
 	}
 }

Component s that implement the CommandLineRunner interface will be completed after all Spring Beans are initialized and before SpringApplication.run() is executed. Next, verify our test by adding two lines of printing.

@SpringBootAppliction
public class DemoApplication {
    
	public static void main(String[] args){
		System.out.println("... start SpringAppliction.run()");
		SpringAppliction.run(DemoAppliction.class, args);
		System.out.println("... end SpringAppliction.run()");
	}
}

The console prints as follows.

... start SpringAppliction.run()

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.5.RELEASE)

2020-03-09 10:37:13.537  INFO 13456 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication on DESKTOP-9P44RJ5 with PID 13456 (D:\work\workspace\demo\target\classes started by 78787 in D:\work\workspace\demo)
2020-03-09 10:37:13.539  INFO 13456 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2020-03-09 10:37:14.131  INFO 13456 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-03-09 10:37:14.137  INFO 13456 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-03-09 10:37:14.141  INFO 13456 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.31]
2020-03-09 10:37:14.203  INFO 13456 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-03-09 10:37:14.203  INFO 13456 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 638 ms
2020-03-09 10:37:14.307  INFO 13456 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-03-09 10:37:14.404  INFO 13456 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-03-09 10:37:14.406  INFO 13456 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.094 seconds (JVM running for 1.754)
... init resources by implements CommandLineRunner
... end SpringAppliction.run()

ApplicationRunner

  • Define the initialization class MyApplicationRunner
  • Implement the ApplicationRunner interface and its run() method, in which the initialization logic is written
  • Register as a Bean and add @ Component annotation
  • The sample code is as follows
[@Component](https://my.oschina.net/u/3907912)
public class MyApplicationRunner implements ApplicationRunner {
 
    [@Override](https://my.oschina.net/u/1162528)
    public void run(ApplicationArguments applicationArguments) throws Exception {
        System.out.println("...init resources by implements ApplicationRunner");
    }
}

It can be seen that both the implementation of the application runner interface and the implementation of the CommandLineRunner interface can complete the initialization operation of the project and achieve the same effect. The only difference between the two methods before is that the parameters in the run() method are different. In CommandLineRunner, they are just simple String... args parameters, while in ApplicationRunner, they contain ApplicationArguments objects, which can help to get richer project information.

public interface ApplicationArguments {
    String[] getSourceArgs();

    Set<String> getOptionNames();

    boolean containsOption(String name);

    List<String> getOptionValues(String name);

    List<String> getNonOptionArgs();
}

@Order

If there are initialization classes that implement both the ApplicationRunner interface and the CommandLineRunner interface in the project, which one will be executed first? The test tells us that the answer is to implement the initialization class of the ApplicationRunner interface first. I don't think you need to pay too much attention to this point. But if you need to change the default execution Order between the two initialization classes, the @ Order annotation can help us solve this problem.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {
    int value() default 2147483647;
}

@Component
@Order(1)
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("... init resources by implements CommandLineRunner");
    }
}

@Component
@Order(2)
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("... init resources by implements ApplicationRunner");
    }
}

Finally, the console prints as follows, and we find that, @Order The smaller the annotation value, the earlier the initialization class executes.

....(Omit some codes)
2020-03-09 10:41:34.858  INFO 20256 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.151 seconds (JVM running for 1.821)
... init resources by implements CommandLineRunner
... init resources by implements ApplicationRunner
... end SpringAppliction.run()

@PostConstruct

The @ PostConstruct annotation can also help us to initialize resources, provided that these initialization operations do not need to rely on the initialization work of other spring beans.

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

@Component
public class Test {

    @PostConstruct
    public void testPostConstruct(){
        System.out.println("... post construct ");
    }
}

To start the project, the console prints as follows.

2020-03-09 10:49:34.229  INFO 24996 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 603 ms
... post construct 
2020-03-09 10:49:34.322  INFO 24996 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-03-09 10:49:34.412  INFO 24996 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-03-09 10:49:34.414  INFO 24996 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.031 seconds (JVM running for 1.697)
... init resources by implements CommandLineRunner
... init resources by implements ApplicationRunner
... end SpringAppliction.run()

Summary at the end of the article

To sum up, the Order of initialization operations with @ PostConstruct annotation is the fastest, provided that these operations cannot depend on the initialization of other beans. By adding the @ Order annotation, we can change the loading Order of different beans at the same level.

Tags: Programming Tomcat Spring Apache jvm

Posted on Mon, 09 Mar 2020 01:37:29 -0400 by ashishag67