SpringBoot的重要类及接口
ApplicationContextInitializer
首先看spring官网的介绍:
翻译下来就是说:
- 用于在spring容器刷新之前初始化Spring ConfigurableApplicationContext的回调接口。(就是在容器刷新之前调用该类的 initialize 方法。并将 ConfigurableApplicationContext 类的实例传递给该方法)
- 通常用于需要对应用程序上下文进行编程初始化的web应用程序中。例如,根据上下文环境注册属性源或激活配置文件等。
- 可排序的(实现Ordered接口,或者添加@Order注解)
ApplicationContextInitializer三种实现方式
首先新建一个类 MyApplicationContextInitializer并实现 ApplicationContextInitializer 接口。
public class MyApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("-----MyApplicationContextInitializer initialize-----"); } }
1、main函数中添加
@SpringBootApplication public class MySpringBootApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(MySpringBootApplication.class); application.addInitializers(new MyApplicationContextInitializer()); application.run(args); } }
2、配置文件中配置
context.initializer.classes=org.springframework.boot.demo.common.MyApplicationContextInitializer
3、SpringBoot的SPI扩展---META-INF/spring.factories中配置
org.springframework.context.ApplicationContextInitializer=org.springframework.boot.demo.common.MyApplicationContextInitializer
排序问题
给 MyApplicationContextInitializer 加上Order注解:我们指定其拥有最高的排序级别。(值越小越早执行)
@Order(Ordered.HIGHEST_PRECEDENCE) public class MyApplicationContextInitializer implements ApplicationContextInitializer{ @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("-----MyApplicationContextInitializer initialize-----"); } }
除了使用Order注解,还可以采用实现Ordered接口的方式,排序验证结果都是一样的。
通过源码分析ApplicationContextInitializer何时被调用
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { return run(new Class[]{primarySource}, args); } public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); } public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); // this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
在SpringBoot 2.3.6.RELEASE版本中,在this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);方法中调用。
ApplicationRunner or CommandLineRunner
应用服务启动时,加载一些数据和执行一些应用的初始化动作。如:删除临时文件,清除缓存信息,读取配置文件信息,数据库连接等。
SpringBoot提供了CommandLineRunner和ApplicationRunner接口。当接口有多个实现类时,提供了@order注解实现自定义执行顺序,也可以实现Ordered接口来自定义顺序。
注意:数字越小,优先级越高,也就是@Order(1)注解的类会在@Order(2)注解的类之前执行。
两者的区别在于:
ApplicationRunner中run方法的参数为ApplicationArguments,而CommandLineRunner接口中run方法的参数为String数组。想要更详细地获取命令行参数,那就使用ApplicationRunner接口。
ApplicationRunner
@Component @Order(value = 10) public class AgentApplicationRun2 implements ApplicationRunner { @Override public void run(ApplicationArguments applicationArguments) throws Exception { } }
CommandLineRunner
@Component @Order(value = 11) public class AgentApplicationRun implements CommandLineRunner { @Override public void run(String... strings) throws Exception { } }
接口不同于:
ApplicationRunner中run方法的参数为ApplicationArguments,而CommandLineRunner接口中run方法的参数为String数组。