实际应用通常需要在应用启动后实现一定业务逻辑,Spring Boot提供了几种方式实现,本文分别进行介绍并对比其中的差异。
1. 环境准备
Spring Boot是一个开发框架,当启动时需要一定启动时间。如果在任何构造函数中实现一些初始化代码,可能会遇到其依赖的对象还没有被初始化。
我们讨论的问题就是在Spring context初始化之后,运行自定义初始化代码。Spring Boot提供了几种方式实现,下面首先搭建一个示例工程。
启动类的非常简单:
@SpringBootApplication
public class InitializeApplication {
public static void main(String[] args) {
SpringApplication.run(InitializeApplication.class,args);
}
}
相应pom.xml主要内容:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dataz</groupId>
<artifactId>init-code</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>init-code</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是可以启动应用程序,直接运行InitializeApplication类。应该可以看到Spring Boot在控制台启动了,可能需要几秒时间。
2. 实现初始化业务
2.1 使用ApplicationListener 方法
现在我们新增一个组件类:
@Component
@Slf4j
public class ApplicationListenerInitialize implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
log.info("I waited until Spring Boot finished before getting here!");
}
}
该类实现了接口ApplicationListener,它可以处理不同类型的事件,使用类型参数指定监听特定事件。这里我们监听ContextRefreshedEvent事件,顾名思义,即Spring Boot应用上下文被刷新或初始化后触发。
和其他接口一样,ApplicationListener接口必须实现方法onApplicationEvent().上面示例当触发事件时仅打印日志,实际应用中可以实现更复杂的业务。
完成上面工作后,启动应用并检查控制台,显示内容如下:
我们看到在初始化过程结束之后,方法被执行并打印日志。但不在最后,其之后还有一行框架打印的日志。如果你希望所有事情都已经初始化完成才开始执行我们的方法,如何实现?可以可以简单监听另一个事件ApplicationReadyEvent,代替刚才的 ContextRefreshedEvent事件。再次启动应用检查控制台日志:
很好,确实在最后打印日志了。通过监听特定事件可以实现在所有启动完成之后才执行初始化业务代码。
同样我们也可以通过Spring 提供的@EventListener注解来实现:
@Slf4j
@Component
public class EventListenerInitialize {
@EventListener(ApplicationReadyEvent.class)
public void initializeSomething() {
log.info("I am now initializing something!");
}
该方法与上面的一样,至少通过注解实现,运行后控制台如下图:
2.2 CommandLineRunner 接口
我们也可以使用CommandLineRunner 接口运行初始化代码。与ApplicationListener一样,需要实现其对应方法:
@Slf4j
public class CommandInitApplication implements CommandLineRunner {
@Override
public void run(String... args) {
log.info("Command line exec here!");
}
}
run方法实现一些初始化业务代码,这里仅打印日志,启动查看运行日志.
2.3 SmartInitializingSingleton 接口
最后还介绍一个接口SmartInitializingSingleton ,Spring框架提供用于初始化业务实现。还是写一个类实现其唯一方法:
@Slf4j
@Component
public class AppConfig implements SmartInitializingSingleton{
@Override
public void afterSingletonsInstantiated() {
log.info("This was from the smart initializing bean");
}
}
不再重复解释,直接启动查看控制台日志:
该方法运行在上下文初始化之后,并不是应用准备好之后。如果使用该方法需要了解这点。
3. 总结
本文介绍了Spring Boot应用程序中运行初始化代码的三不同方式。
本文参考链接:https://blog.csdn.net/neweastsun/article/details/110235624