Java中的事件监听机制定义了以下几个角色:
①事件:Event,继承 java.util.EventObject 类的对象
②事件源:Source ,任意对象Object
③监听器:Listener,实现 java.util.EventListener 接口 的对象
SpringBoot 在项目启动时,会对几个监听器进行回调,我们可以实现这些监听器接口,在项目启动时完成一些操作。
下面我们来编写实现监听器接口。
package com.lijw.springbootlistener.listener;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("ApplicationContextInitializer initialize...");
}
}
package com.lijw.springbootlistener.listener;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;
import java.time.Duration;
@Component
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
System.out.println("SpringApplicationRunListener starting..");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
System.out.println("SpringApplicationRunListener environmentPrepared..");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener contextPrepared");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener contextLoaded");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("SpringApplicationRunListener started");
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("SpringApplicationRunListener ready");
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener running");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("SpringApplicationRunListener failed");
}
}
package com.lijw.springbootlistener.listener;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner run");
}
}
package com.lijw.springbootlistener.listener;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner run");
}
}
也就说明:MyApplicationRunner和MyCommandLineRunner都是当项目启动后执行,一般我们可以将缓存预热之类的操作放到这里执行。
那么另外的两个监听器要怎么才会启动监听呢?这个先不急,我们来看看 MyApplicationRunner和MyCommandLineRunner 的参数怎么用。
// 项目启动后执行
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner run... args: " + Arrays.asList(args));
}
}
// 项目启动后执行
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner run... args: " + Arrays.asList(args.getSourceArgs()));
}
}
打印信息如下:
可以看到,现在传递的参数为空数组。
如果需要传递参数,则是可以配置在项目的启动命令上。
此时,再启动服务,我们来看看传递的参数如下:
org.springframework.context.ApplicationContextInitializer=com.lijw.springbootlistener.listener.MyApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=com.lijw.springbootlistener.listener.MySpringApplicationRunListener
此时,我们再执行启动服务,可以发现报错如下:
// main方法中出现异常,异常由于接口MySpringApplicationRunListener实现类报错
Exception in thread "main" java.lang.IllegalArgumentException: Cannot instantiate interface org.springframework.boot.SpringApplicationRunListener : com.lijw.springbootlistener.listener.MySpringApplicationRunListener
at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:456)
at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:438)
at org.springframework.boot.SpringApplication.getRunListeners(SpringApplication.java:426)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:293)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at com.lijw.springbootlistener.SpringbootListenerApplication.main(SpringbootListenerApplication.java:10)
// MySpringApplicationRunListener报错的类型为缺少方法,缺少了 <init>(org.springframework.boot.SpringApplication, [Ljava.lang.String;) 也就是缺少了 构造器方法。
Caused by: java.lang.NoSuchMethodException: com.lijw.springbootlistener.listener.MySpringApplicationRunListener.<init>(org.springframework.boot.SpringApplication, [Ljava.lang.String;)
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:451)
... 6 more
Process finished with exit code 1
在查看如何设置构造器的方法上,我们可以查看这个接口的其他实现类:
package com.lijw.springbootlistener.listener;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import java.time.Duration;
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
public MySpringApplicationRunListener(SpringApplication application, String[] args){
}
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
System.out.println("SpringApplicationRunListener starting..");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
System.out.println("SpringApplicationRunListener environmentPrepared..");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener contextPrepared");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener contextLoaded");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("SpringApplicationRunListener started");
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("SpringApplicationRunListener ready");
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener running");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("SpringApplicationRunListener failed");
}
}
执行打印的日志:
SpringApplicationRunListener starting..
SpringApplicationRunListener environmentPrepared..
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.4)
ApplicationContextInitializer initialize...
SpringApplicationRunListener contextPrepared
2022-02-27 08:54:55.785 INFO 15164 --- [ main] c.l.s.SpringbootListenerApplication : Starting SpringbootListenerApplication using Java 1.8.0_91 on regalli-NB0 with PID 15164 (D:\javaProject\maven-practice01\springboot-listener\target\classes started by lijw in D:\javaProject\maven-practice01)
2022-02-27 08:54:55.785 INFO 15164 --- [ main] c.l.s.SpringbootListenerApplication : No active profile set, falling back to 1 default profile: "default"
SpringApplicationRunListener contextLoaded
2022-02-27 08:54:56.255 INFO 15164 --- [ main] c.l.s.SpringbootListenerApplication : Started SpringbootListenerApplication in 0.9 seconds (JVM running for 1.838)
SpringApplicationRunListener started
ApplicationRunner run... args: [name=libai, age=32]
CommandLineRunner run... args: [name=libai, age=32]
SpringApplicationRunListener ready
Process finished with exit code 0