书接上回,我们总结了Spring Boot启动过程中都干了些什么,大致分为环境配置、IOC容器bean加载、事件通知等,具体详细总结可自行调转查看。今天我们来看看一个平时在业务开发中常见的逻辑场景。在开发 Spring Boot 应用时,我们经常需要在项目启动时执行一些初始化逻辑,比如加载缓存、连接外部系统、初始化配置信息等。Spring Boot 提供了多种实现方式,允许我们在应用启动的不同阶段插入代码逻辑。本文将结合启动过程详细介绍这些方式,并说明适用的场景及实现示例。
接下来我将一一讲述实现方式,这些操作的源码流程已经在启动过程总结一文中详细叙述过, 这里就只做定义解析和案例展示了,关于源码实现细节可跳转链接查看哈。
1. 使用 CommandLineRunner 和 ApplicationRunner
CommandLineRunner
和 ApplicationRunner
是 Spring Boot 提供的两个接口,用于在应用启动完成后执行逻辑。
CommandLineRunner
接收String[] args
参数,适合处理简单的启动参数。ApplicationRunner
接收ApplicationArguments
对象,方便解析复杂参数。
CommandLineRunner 示例:
java
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 逻辑!");
for (String arg : args) {
System.out.println("启动参数:" + arg);
}
}
}
ApplicationRunner 示例:
java
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 逻辑!");
if (args.containsOption("debug")) {
System.out.println("调试模式启动!");
}
}
}
适用场景: 在项目启动后立即执行初始化逻辑,例如加载缓存或注册服务。这是笔者比较推荐的方式,用的最多~~~
2. 使用 ApplicationListener 监听启动事件
Spring 提供了丰富的 事件机制 。通过实现 ApplicationListener
接口,我们可以监听应用启动的各个阶段事件,如 ApplicationReadyEvent
。
示例:
typescript
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("应用启动完成,执行 ApplicationReadyEvent 事件监听逻辑!");
}
}
适用场景: 当需要在应用完全启动后执行某些操作,如向监控系统注册实例。
3. 使用 @EventListener 注解
@EventListener
注解是一种简化的事件监听机制,允许我们用注解监听特定事件。
java
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyEventListener {
@EventListener(ApplicationStartedEvent.class)
public void onApplicationStarted() {
System.out.println("Spring Boot 启动时,执行 ApplicationStartedEvent 监听逻辑!");
}
}
适用场景: 适用于监听特定事件,如应用启动或关闭时的操作。
上面使用监听事件的两种方式分别监听了事件ApplicationReadyEvent
和ApplicationStartedEvent
,同类型的事件如下所示,这里就不一一讲述了,感兴趣的可自行写写示例体会下。
项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用
Github地址 :github.com/plasticene/...
Gitee地址 :gitee.com/plasticene3...
微信公众号 :Shepherd进阶笔记
交流探讨qun:Shepherd_126
4. 使用 @PostConstruct 注解
@PostConstruct
注解用于在 Bean 初始化完成后执行逻辑。这是一个标准的 Java 注解,Spring 会在依赖注入完成后调用它标注的方法。
示例:
kotlin
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
@Service
public class MyService {
@PostConstruct
public void init() {
System.out.println("Bean 初始化完成后执行 @PostConstruct 方法!");
}
}
适用场景: 当需要在某个 Bean 初始化完成后执行逻辑,比如连接数据库、加载外部资源等。
5. 使用 BeanPostProcessor
BeanPostProcessor
接口允许我们在 Bean 初始化前后插入逻辑。
示例:
typescript
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化前处理 Bean:" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化后处理 Bean:" + beanName);
return bean;
}
}
适用场景: 当需要对某些 Bean 的初始化过程进行增强时。
6. 使用 InitializingBean 接口
InitializingBean
接口中的 afterPropertiesSet()
方法会在 Bean 的属性设置完成后执行。
示例:
java
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class MyInitializingBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Bean 属性设置完成,执行 afterPropertiesSet() 方法!");
}
}
适用场景: 当需要在 Bean 初始化后执行一些逻辑。
7. 使用 SmartInitializingSingleton 接口
SmartInitializingSingleton
是一个特殊接口,当 所有单例 Bean 初始化完成后 ,会触发 afterSingletonsInstantiated()
方法。
示例:
typescript
import org.springframework.context.SmartInitializingSingleton;
import org.springframework.stereotype.Component;
@Component
public class MySmartInitializingSingleton implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
System.out.println("所有单例 Bean 初始化完成,执行 afterSingletonsInstantiated() 方法!");
}
}
适用场景: 当需要确保所有单例 Bean 初始化完成后再执行操作。
8. 在 main 方法中执行逻辑
在 Spring Boot 应用的入口方法 main
中,我们也可以执行一些初始化逻辑。
示例:
typescript
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
System.out.println("Spring Boot 启动前,执行自定义逻辑!");
SpringApplication.run(MyApplication.class, args);
System.out.println("Spring Boot 启动后,执行自定义逻辑!");
}
}
适用场景: 当需要在应用启动的前后执行全局逻辑时。
总结
实现方式 | 触发时机 | 适用场景 |
---|---|---|
CommandLineRunner |
应用启动完成后 | 需要执行启动参数相关逻辑 |
ApplicationRunner |
应用启动完成后 | 更方便处理复杂启动参数 |
@PostConstruct |
Bean 初始化完成后 | Bean 的初始化逻辑 |
ApplicationListener |
特定事件触发时 | 监听应用启动或关闭的事件 |
@EventListener |
特定事件触发时 | 使用注解简化事件监听 |
BeanPostProcessor |
Bean 初始化前后 | 增强 Bean 的初始化过程 |
InitializingBean |
Bean 属性设置完成后 | 属性注入后的初始化逻辑 |
SmartInitializingSingleton |
所有单例 Bean 初始化完成后 | 所有 Bean 完成初始化后的逻辑 |
main方法 |
应用启动前后 | 在应用启动前或启动后执行全局逻辑 |
选择合适的实现方式
- 需要在应用启动后立即执行逻辑 :
CommandLineRunner
或ApplicationRunner
- 需要监听应用的启动事件 :
ApplicationListener
或@EventListener
- 需要对 Bean 初始化过程进行控制 :
@PostConstruct
或BeanPostProcessor
- 需要确保所有 Bean 初始化完成后再执行逻辑 :
SmartInitializingSingleton
不同的实现方式适用于不同的场景,我们可以根据业务需求选择合适的方式,将逻辑插入到 Spring Boot 启动的不同阶段。