Spring Boot 启动输出一句话
admin 发布于:2022-05-09 10:35:57
阅读:loading
在Spring Boot启动过程中做一些程序初始化的动作是一个比较常规的事情,这里就以程序启动输出一句话作为实际监听启动过程中的业务逻辑。总共整理了几种常见的实现方式来分别实现(未使用Web环境依赖的Servlet、Filter),主要以Java和Spring环境相关的实现方式,参考实现方式如下:
(1)启动类输出,这种输出方式拥有绝对的最先触发和最后触发,实现参考如下:
/**
* 启动类
*
* @author chendd
* @date 2022/5/8 20:09
*/
@SpringBootApplication
@Import(value = ContextConfiguration.class)
public class Bootstrap {
/**
* 服务器启动
* @param args 启动参数
*/
public static void main(String[] args) {
SoutCounter.sign("Bootstrap.main###启动类启动前输出一句话");
SpringApplication.run(Bootstrap.class , args);
SoutCounter.sign("Bootstrap.main###启动类启动后输出一句话");
}
}
(2)Spring组件的构造函数触发,构造函数的方式优先于其它各种触发逻辑;
(3)@PostConstruct注解触发,注意该注解是JDK内置的并非Spring提供,触发时机为当前组件类初始化完成后触发,实现参考如下:
package cn.chendd.modules.sout;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* 普通组件
*
* @author chendd
* @date 2022/5/25 21:48
*/
@Component
public class SoutComponent {
public SoutComponent() {
SoutCounter.sign("SoutComponent###使用构造函数输出");
}
@PostConstruct
public void postVonstruct() {
SoutCounter.sign("SoutComponent.postVonstruct###使用@PostConstruct输出");
}
}
(4)实现InitializingBean接口注册Bean组件,并重写afterPropertiesSet方法执行输出,实现参考如下:
package cn.chendd.modules.sout;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* 使用InitializingBean
*
* @author chendd
* @date 2022/5/25 22:46
*/
@Component
public class SoutInitializingBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
SoutCounter.sign("SoutInitializingBean使用InitializingBean输出");
}
}
(5)使用监听器Listener来监控服务器启动进度实现输出,在ApplicationListener的泛型支持的实现类中支持多种启动事件的监听,本文逻辑其中三种事件监听来验证实现,分别是:ApplicationStartedEvent、ApplicationReadyEvent、ContextRefreshedEvent,分别是:服务器启动后触发监听、服务器环境启动好触发监听、Spring容器上下文刷新触发监听,请注意上下文刷新事件ContextRefreshedEvent可能会执行多次,若使用该事件作为初始化的功能时需要处理重复执行的场景,实现参考如下:
package cn.chendd.modules.sout;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
* 启动监听器
*
* @author chendd
* @date 2022/5/25 22:16
*/
@Configuration
public class SoutApplicationListener {
@Component
public static class SoutApplicationStartingListener implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
SoutCounter.sign("SoutApplicationListener$ApplicationStartedEvent###使用ApplicationStartedEvent监听器输出");
}
}
@Component
public static class SoutApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
SoutCounter.sign("SoutApplicationListener$SoutApplicationReadyListener###使用ApplicationReadyEvent监听器输出");
}
}
@Component
public static class SoutContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
SoutCounter.sign("SoutApplicationListener$SoutContextRefreshedEventListener###使用ContextRefreshedEvent监听器输出");
}
}
}
(6)使用CommandLineRunner接口实现run方法实现输出,最初发现该种实现方式还是在翻阅Spring官网提供的子项目示例中看到的这种初始化方式,借着本次实践特整理出来,run方法的args参数等同于启动类的指定的args,实现参考如下:
package cn.chendd.modules.sout;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 使用CommandLineRunner输出
*
* @author chendd
* @date 2022/5/25 22:29
*/
@Component
@Order(101)
public class SoutCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
//此处args等同于启动类main的参数
SoutCounter.sign("SoutCommandLineRunner使用CommandLineRunner输出");
}
}
(7)使用SoutApplicationRunner接口实现run方法实现输出,这种实现与上述CommandLineRunner接口的实现比较相似,推荐使用这种方式,因为在它的run方法参数类型为ApplicationArguments,除了可以拿到应用程序main函数启动时的args外,还可以获取到sourceArgs、optionNames、optionValues等启动参数,实现参考如下:
package cn.chendd.modules.sout;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 使用ApplicationRunner
*
* @author chendd
* @date 2022/5/25 22:52
*/
@Component
@Order(102)
public class SoutApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
SoutCounter.sign("SoutApplicationRunner使用ApplicationRunner输出");
}
}
程序技术器
package cn.chendd.modules.sout;
import java.util.concurrent.atomic.AtomicLong;
/**
* 启动时运行方法的计数器
*
* @author chendd
* @date 2022/5/25 21:50
*/
public class SoutCounter {
/**
* 默认构造计数器
*/
private static final AtomicLong COUNTER = new AtomicLong();
/**
* 加1后返回
* @return 计数器的值
*/
private static Long add() {
return COUNTER.addAndGet(1);
}
public static void sign(String location) {
String message = String.format("%1$s,执行顺序:%2$d" , location , add());
System.err.println(message);
}
}
程序输出结果
其它注意
(1)一些同类型的组件的初始化执行顺序默认以扫描包的优先级触发,可使用@Order注解设置优先顺序;
(2)未使用BeanPostProcessor这种所有初始化均触发的启动实现;
源码工程下载:源码下载.zip;
点赞