1. 实现ServletContextListener接口
@Componentpublic class SpringBootInitialization1 implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("方式一:实现ServletContextListener接口");}}
2. 实现ApplicationListener接口
@Componentpublic class SpringBootInitialization2 implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {System.out.println("方式四:实现ApplicationListener<ContextRefreshedEvent>接口");}}
3. 实现ServletContextAware接口
@Componentpublic class SpringBootInitialization3 implements ServletContextAware {@Overridepublic void setServletContext(ServletContext servletContext) {System.out.println("方式三:实现ServletContextAware接口");}}
4. 方法上加注解@PostConstruct
@Componentpublic class SpringBootInitialization4 {@PostConstructpublic static void init() {System.out.println("方式二:方法上加注解@PostConstruct");}}
5. 实现ApplicationRunner接口
@Componentpublic class SpringBootInitialization5 implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("方式五:实现ApplicationRunner接口");}}
6. 实现CommandLineRunner接口
@Componentpublic class SpringBootInitialization6 implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("方式六:实现CommandLineRunner接口");}}
7. 实现InitializingBean接口
@Componentpublic class SpringBootInitialization7 implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("方式七:实现InitializingBean接口");}}
以上加载方法的顺序
package com.ipebg.config;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.InitializingBean;import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.boot.CommandLineRunner;import org.springframework.context.ApplicationListener;import org.springframework.context.event.ContextRefreshedEvent;import org.springframework.stereotype.Component;import org.springframework.web.context.ServletContextAware;import javax.annotation.PostConstruct;import javax.servlet.ServletContext;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener;/*** 2021/3/9 上午 11:02*/@Slf4j@Componentpublic class TestInit implements InitializingBean, CommandLineRunner, ApplicationRunner,ApplicationListener<ContextRefreshedEvent>, ServletContextAware, ServletContextListener {public TestInit() {log.error("++ TestInit construct... ++");}@Overridepublic void afterPropertiesSet() throws Exception {log.error("++ InitializingBean afterPropertiesSet... ++");}/*** Callback used to run the bean.** @param args incoming application arguments* @throws Exception on error*/@Overridepublic void run(ApplicationArguments args) throws Exception {log.error("++ ApplicationRunner run... ++");}/*** Callback used to run the bean.** @param args incoming main method arguments* @throws Exception on error*/@Overridepublic void run(String... args) throws Exception {log.error("++ CommandLineRunner run... ++");}@Overridepublic void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {log.error("++ ApplicationListener<ContextRefreshedEvent> onApplicationEvent... ++");}@Overridepublic void setServletContext(ServletContext servletContext) {log.error("++ ServletContextAware setServletContext... ++");}@Overridepublic void contextInitialized(ServletContextEvent sce) {log.error("++ ServletContextListener contextInitialized... ++");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {log.error("++ ServletContextListener contextDestroyed... ++");}@PostConstructpublic void init(){log.error("++ PostConstruct init... ++");}}
...Tomcat initialized with port(s): 8082 (http)++ TestInit construct... ++++ ServletContextAware setServletContext... ++++ PostConstruct init... ++++ InitializingBean afterPropertiesSet... ++++ ServletContextListener contextInitialized... ++...++ ApplicationListener<ContextRefreshedEvent> onApplicationEvent... ++Tomcat started on port(s): 8082 (http) with context path ''++ ApplicationRunner run... ++++ CommandLineRunner run... ++Bean初始化-依赖注入(如果有依赖其他Bean)-ServletContextAware-@PostConstruct-InitializingBean接口ServletContextListener-ApplicationListener<ContextRefreshedEvent>-ApplicationRunner接口-CommandLineRunner接口
@PostConstruct 服务初始化过程中,执行该方法,该方法不结束无法提供服务
实现CommandLineRunner接口 服务初始化之后,执行方法
@order
如果项目中既有实现了 ApplicationRunner 接口的初始化类,又有实现了 CommandLineRunner 接口的初始化类,那么会是哪一个先执行呢?测试告诉我们,答案是实现了 ApplicationRunner 接口的初始化类先执行,我想这点倒是不需要大家过分去关注为什么。但如果需要改变两个初始化类之间的默认执行顺序,那么使用 @Order 注解就可以帮助我们解决这个问题。
@Component@Order(1)//order的值越小,该初始化类也就越早执行。public class MyCommandLineRunner implements CommandLineRunner {...}
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方法可以接收一个字符串的数组。
如果想要指定他们的顺序,可以有如下选择:
- 额外指定实现
org.springframework.core.Ordered接口。 - 使用
org.springframework.core.annotation.Order注解。
