Spring Boot 中初始化资源的几种方式

假设有这么一个需求,要求在项目启动过程当中,完成线程池的初始化,加密证书加载等功能,你会怎样作?若是没有想好答案,请接着往下看。今天介绍几种在Spring Boot中进行资源初始化的方式,帮助你们解决和回答这个问题。java

CommandLineRunner

  • 定义初始化类 MyCommandLineRunnerweb

  • 实现 CommandLineRunner 接口,并实现它的 run() 方法,在该方法中编写初始化逻辑apache

  • 注册成 Bean,添加 @Component 注解tomcat

  • 示例代码以下:app

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

实现了 CommandLineRunner 接口的 Component 会在全部 Spring Beans 初始化完成以后,在 SpringApplication.run() 执行以前完成。下面经过加两行打印来验证咱们的测试。ide

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

控制台打印结果以下。post

... start SpringApplication.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 SpringApplication.run()

ApplicationRunner

  • 定义初始化类 MyApplicationRunner
  • 实现 ApplicationRunner 接口,并实现它的 run() 方法,在该方法中编写初始化逻辑
  • 注册成 Bean,添加 @Component 注解便可
  • 示例代码以下
@Component
public class MyApplicationRunner implements ApplicationRunner {
 
    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        System.out.println("...init resources by implements ApplicationRunner");
    }
}

​ 能够看到,经过实现 ApplicationRunner 接口,和经过实现 CommandLineRunner 接口均可以完成项目的初始化操做,实现相同的效果。二者以前惟一的区别是 run() 方法中自带的形参不一样,在 CommandLineRunner 中只是简单的 String... args 形参,而 ApplicationRunner 中是包含了 ApplicationArguments 对象,能够帮助获取更丰富的项目信息。测试

public interface ApplicationArguments {
    String[] getSourceArgs();

    Set<String> getOptionNames();

    boolean containsOption(String name);

    List<String> getOptionValues(String name);

    List<String> getNonOptionArgs();
}

@Order

​ 若是项目中既有实现了 ApplicationRunner 接口的初始化类,又有实现了 CommandLineRunner 接口的初始化类,那么会是哪个先执行呢?测试告诉咱们,答案是实现了 ApplicationRunner 接口的初始化类先执行,我想这点却是不须要你们过度取关注为何,但若是须要改变两个初始化类之间的默认执行顺序,那么使用 @Order 注解就能够帮助咱们解决这个问题。加密

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

​ 最终,控制台打印以下,经过控制台输出咱们发现,@Order 注解值越小,该初始化类也就越早执行。spa

....(省略部分代码)
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

​ 使用 @PostConstruct 注解一样能够帮助咱们完成资源的初始化操做,前提是这些初始化操做不须要依赖与其余 Spring Bean 的初始化工做。

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

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

​ 启动项目,控制台打印以下。

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()

文末小结

​ 综上,使用 @PostConstruct 注解进行初始化操做的顺序是最快的,前提是这些操做不能依赖于其它Bean的初始化完成。经过添加 @Order 注解,咱们能够改变同层级之间不一样Bean的加载顺序。

相关文章
相关标签/搜索