1. 实现ServletContextListener接口

  1. @Component
  2. public class SpringBootInitialization1 implements ServletContextListener {
  3. @Override
  4. public void contextInitialized(ServletContextEvent sce) {
  5. System.out.println("方式一:实现ServletContextListener接口");
  6. }
  7. }

2. 实现ApplicationListener接口

  1. @Component
  2. public class SpringBootInitialization2 implements ApplicationListener<ContextRefreshedEvent> {
  3. @Override
  4. public void onApplicationEvent(ContextRefreshedEvent event) {
  5. System.out.println("方式四:实现ApplicationListener<ContextRefreshedEvent>接口");
  6. }
  7. }

3. 实现ServletContextAware接口

  1. @Component
  2. public class SpringBootInitialization3 implements ServletContextAware {
  3. @Override
  4. public void setServletContext(ServletContext servletContext) {
  5. System.out.println("方式三:实现ServletContextAware接口");
  6. }
  7. }

4. 方法上加注解@PostConstruct

  1. @Component
  2. public class SpringBootInitialization4 {
  3. @PostConstruct
  4. public static void init() {
  5. System.out.println("方式二:方法上加注解@PostConstruct");
  6. }
  7. }

5. 实现ApplicationRunner接口

  1. @Component
  2. public class SpringBootInitialization5 implements ApplicationRunner {
  3. @Override
  4. public void run(ApplicationArguments args) throws Exception {
  5. System.out.println("方式五:实现ApplicationRunner接口");
  6. }
  7. }

6. 实现CommandLineRunner接口

  1. @Component
  2. public class SpringBootInitialization6 implements CommandLineRunner {
  3. @Override
  4. public void run(String... args) throws Exception {
  5. System.out.println("方式六:实现CommandLineRunner接口");
  6. }
  7. }

7. 实现InitializingBean接口

  1. @Component
  2. public class SpringBootInitialization7 implements InitializingBean {
  3. @Override
  4. public void afterPropertiesSet() throws Exception {
  5. System.out.println("方式七:实现InitializingBean接口");
  6. }
  7. }

以上加载方法的顺序

  1. package com.ipebg.config;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.beans.factory.InitializingBean;
  4. import org.springframework.boot.ApplicationArguments;
  5. import org.springframework.boot.ApplicationRunner;
  6. import org.springframework.boot.CommandLineRunner;
  7. import org.springframework.context.ApplicationListener;
  8. import org.springframework.context.event.ContextRefreshedEvent;
  9. import org.springframework.stereotype.Component;
  10. import org.springframework.web.context.ServletContextAware;
  11. import javax.annotation.PostConstruct;
  12. import javax.servlet.ServletContext;
  13. import javax.servlet.ServletContextEvent;
  14. import javax.servlet.ServletContextListener;
  15. /**
  16. * 2021/3/9 上午 11:02
  17. */
  18. @Slf4j
  19. @Component
  20. public class TestInit implements InitializingBean, CommandLineRunner, ApplicationRunner,
  21. ApplicationListener<ContextRefreshedEvent>, ServletContextAware, ServletContextListener {
  22. public TestInit() {
  23. log.error("++ TestInit construct... ++");
  24. }
  25. @Override
  26. public void afterPropertiesSet() throws Exception {
  27. log.error("++ InitializingBean afterPropertiesSet... ++");
  28. }
  29. /**
  30. * Callback used to run the bean.
  31. *
  32. * @param args incoming application arguments
  33. * @throws Exception on error
  34. */
  35. @Override
  36. public void run(ApplicationArguments args) throws Exception {
  37. log.error("++ ApplicationRunner run... ++");
  38. }
  39. /**
  40. * Callback used to run the bean.
  41. *
  42. * @param args incoming main method arguments
  43. * @throws Exception on error
  44. */
  45. @Override
  46. public void run(String... args) throws Exception {
  47. log.error("++ CommandLineRunner run... ++");
  48. }
  49. @Override
  50. public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
  51. log.error("++ ApplicationListener<ContextRefreshedEvent> onApplicationEvent... ++");
  52. }
  53. @Override
  54. public void setServletContext(ServletContext servletContext) {
  55. log.error("++ ServletContextAware setServletContext... ++");
  56. }
  57. @Override
  58. public void contextInitialized(ServletContextEvent sce) {
  59. log.error("++ ServletContextListener contextInitialized... ++");
  60. }
  61. @Override
  62. public void contextDestroyed(ServletContextEvent sce) {
  63. log.error("++ ServletContextListener contextDestroyed... ++");
  64. }
  65. @PostConstruct
  66. public void init(){
  67. log.error("++ PostConstruct init... ++");
  68. }
  69. }
  1. ...
  2. Tomcat initialized with port(s): 8082 (http)
  3. ++ TestInit construct... ++
  4. ++ ServletContextAware setServletContext... ++
  5. ++ PostConstruct init... ++
  6. ++ InitializingBean afterPropertiesSet... ++
  7. ++ ServletContextListener contextInitialized... ++
  8. ...
  9. ++ ApplicationListener<ContextRefreshedEvent> onApplicationEvent... ++
  10. Tomcat started on port(s): 8082 (http) with context path ''
  11. ++ ApplicationRunner run... ++
  12. ++ CommandLineRunner run... ++
  13. Bean初始化-依赖注入(如果有依赖其他Bean)-ServletContextAware-@PostConstruct-InitializingBean接口
  14. ServletContextListener-ApplicationListener<ContextRefreshedEvent>-ApplicationRunner接口-CommandLineRunner接口

@PostConstruct 服务初始化过程中,执行该方法,该方法不结束无法提供服务
实现CommandLineRunner接口 服务初始化之后,执行方法

@order

如果项目中既有实现了 ApplicationRunner 接口的初始化类,又有实现了 CommandLineRunner 接口的初始化类,那么会是哪一个先执行呢?测试告诉我们,答案是实现了 ApplicationRunner 接口的初始化类先执行,我想这点倒是不需要大家过分去关注为什么。但如果需要改变两个初始化类之间的默认执行顺序,那么使用 @Order 注解就可以帮助我们解决这个问题。

  1. @Component
  2. @Order(1)//order的值越小,该初始化类也就越早执行。
  3. public class MyCommandLineRunner implements CommandLineRunner {
  4. ...
  5. }

ApplicationRunner和CommandLineRunner

摘自SpringBoot官方文档:
Tasks expected to run during startup should be executed by CommandLineRunner and ApplicationRunner components instead of using Spring component lifecycle callbacks such as @PostConstruct.
期望在启动期间运行的任务应该由CommandLineRunner和ApplicationRunner组件执行,而不是使用Spring组件生命周期回调,如@PostConstruct。
如果希望在SpringApplication启动后运行一些特定的代码,可以实现ApplicationRunner或CommandLineRunner接口。这两个接口以相同的方式工作,并提供一个run方法,在SpringApplication.run()完成之前调用该方法。
ApplicationRunner的run方法接收一个ApplicationArguments参数,而CommandLineRunner的run方法可以接收一个字符串的数组。
如果想要指定他们的顺序,可以有如下选择:

  1. 额外指定实现org.springframework.core.Ordered接口。
  2. 使用org.springframework.core.annotation.Order注解。