ToB企服应用市场:ToB评测及商务社交产业平台

标题: 京东一面:怎样在SpringBoot启动时执行特定代码?有哪些方式? [打印本页]

作者: 忿忿的泥巴坨    时间: 2024-5-16 23:46
标题: 京东一面:怎样在SpringBoot启动时执行特定代码?有哪些方式?
引言

Spring Boot 提供了许多便捷的功能和特性,使得开发者可以更加轻松地构建强大、高效的应用程序。然而,在应用程序启动时执行一些初始化操作是至关重要的,它可以确保应用程序在启动后处于预期的状态,从而提供更好的用户体验和稳定性。
在应用程序启动时执行初始化操作有许多好处。首先,它可以确保应用程序在启动后的初始状态是正确的,避免了在应用程序运行时出现意外情况。其次,它可以在应用程序准备好接受请求之前完成一些必要的设置,例如加载配置、建立数据库连接、缓存预热等。总的来说,执行初始化操作可以确保应用程序以正确的方式启动,并为后续操作提供一个稳定的基础。

监听 ApplicationContext事故

Spring Boot应用程序启动时执行初始化操作的方法是通过监听ApplicationContext事故。ContextRefreshedEvent事故表现ApplicationContext被初始化或革新时触发的事故。通过监听这个事故,开发者可以在应用程序启动后执行一些必要的初始化操作。

示例:
  1. @Component
  2. public class MyContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {
  3.     @Override
  4.     public void onApplicationEvent(ContextRefreshedEvent event) {
  5.         System.out.println("监听到ContextRefreshedEvent事件,开始初始化操作。。。。。。。");
  6.     }
  7. }
复制代码
这种方式适合以了局景:
这种方式能够确保在 ApplicationContext 被完全初始化或革新后执行初始化操作,可以在这个时机执行一些需要ApplicationContext完全准备好的操作。但是需要注意的是,ContextRefreshedEvent 事故可能会在应用程序的革新周期内多次触发,因此在处置惩罚这个事故时需要谨慎处置惩罚,避免重复执行初始化逻辑。
实现CommandLineRunner接口

CommandLineRunner是Spring Boot提供的一个接口,它有一个run方法,当Spring Boot应用上下文初始化完成后,会自动查找并执行所有实现了CommandLineRunner接口的Bean的run方法。CommandLineRunner接口现实上是Spring Boot对Spring框架生命周期管理的一个扩展,通过对接口的实现,我们可以在Spring Boot应用启动后的特定阶段执行自定义的初始化逻辑。

示例:
  1. @Component
  2. public class MyCommandLineRunner implements CommandLineRunner {
  3.     @Override
  4.     public void run(String... args) throws Exception {
  5.         System.out.println("MyCommandLineRunner.run()方法执行了");
  6.     }
  7. }
复制代码
使用场景:
使用CommandLineRunner接口这种方式是,我们只需要实现接口,无需关注容器的生命周期事故或手动注册监听器。但是假如是多个CommandLineRunner之间的执行顺序无法包管,可能会带来不确定性(假如是不关心顺序,那就不是缺点了)。另外,我们不应该在``
run方法中实现过多或较为复杂的任务。
实现ApplicationRunner接口

ApplicationRunner是Spring Boot提供的另一个接口,它也有一个run方法,与CommandLineRunner接口非常相似。当Spring Boot应用启动而且ApplicationContext初始化完成后,Spring Boot会查找并执行所有实现了ApplicationRunner接口的Bean的run方法。

ApplicationRunner的主要特点是其run方法接收一个ApplicationArguments参数,它可以更好地剖析和处置惩罚命令行参数,包括选项参数(键值对)和非选项参数。
示例:
  1. @Component
  2. public class ApplicationArgumentProcessor implements ApplicationRunner {
  3.     @Override
  4.     public void run(ApplicationArguments args) throws Exception {
  5.         System.out.println("ApplicationArgumentProcessor.run()方法执行了");
  6.     }
  7. }
复制代码
使用场景:
  1. @Component
  2. public class ApplicationArgumentProcessor implements ApplicationRunner {
  3.     @Override
  4.     public void run(ApplicationArguments args) throws Exception {
  5.         Optional<Integer> port = args.getOptionValues("server-port").stream()
  6.                 .map(Integer::parseInt)
  7.                 .findFirst();
  8.         if (port.isPresent()) {
  9.             // 根据端口号进行特定的初始化操作
  10.         }
  11.     }
  12. }
复制代码
相比较于CommandLineRunner,ApplicationRunner提供了更强大的命令行参数剖析功能,可以轻松处置惩罚各种类型的参数。可以根据命令行参数机动调整启动时的初始化逻辑。但是其缺点同CommandLineRunner。
ApplicationRunner和CommandLineRunner都可以用来在Spring Boot启动时执行特定代码,两者在应用场景上略有差别,具体选择哪种取决于项目的现实需求和命令行参数的复杂程度。
使用@PostConstruct注解

@PostConstruct注解是JSR-250规范的一部分,Spring框架对此提供了支持。当Spring容器管理的Bean完成依赖注入后,会自动调用标注有@PostConstruct的方法。这个注解应用于无参或void返回值的方法上,表明该方法应在依赖注入完成后,但在Bean实例正式投入使用之前调用。
在Spring Boot启动时,当Spring容器初始化并创建Bean时,假如发现某个Bean上有@PostConstruct注解的方法,则会在Bean的生命周期的初始化阶段调用这个方法。
  1. @Service
  2. public class UserService {
  3.     @Autowired
  4.     private UserRepository userRepository;
  5.    
  6.     @PostConstruct
  7.     public void init() {
  8.         // 在依赖注入完成后,执行初始化操作
  9.         System.out.println("UserService初始化...");
  10.         // 初始化数据库连接、缓存或者其他内部状态
  11.     }
  12. }
复制代码
使用场景:
@PostConstruct注解只需要在需要执行初始化操作的方法上加上即可,无需额外实现接口或关注Spring容器的生命周期事故。而且针对性强,仅针对单个Bean进行初始化操作,有助于提高代码的模块化和复用性。
但是假如有多个具有@PostConstruct注解的方法,它们之间没有明确的执行顺序,除非通过Bean间的依赖关系隐式确定顺序。而且针对单个Bean进行初始化操作,以是他并不适合做全局性初始化操作。
@Bean注解中指定初始化方法

@Bean注解在Spring框架中用于定义一个Bean的实例化逻辑,通常在配置类中使用。通过在@Bean注解中指定initMethod属性,可以设置一个在Bean实例化并完成依赖注入后执行的方法。当Spring容器创建并注入完所有依赖关系后,会自动调用该Bean上指定的初始化方法。
  1. @Configuration
  2. public class PrePostConfig {
  3.     /**
  4.      * 指定初始化init
  5.      * @return
  6.      */
  7.     @Bean(initMethod = "init")
  8.     BeanWayService beanWayService(){
  9.         return new BeanWayService();
  10.     }
  11. }
  12. public class BeanWayService {
  13.     public void init() {
  14.         System.out.println("@Bean-init-method");
  15.     }
  16.    
  17.     public BeanWayService(){
  18.         super();
  19.         System.out.println("初始化构造函数-BeanWayService");
  20.     }
  21. }
复制代码
适用场景:
Bean实例上定义初始化方法,与Bean紧密关联,可以精确地控制Bean在何时执行初始化操作,与Spring容器的生命周期绑定,尤其适用于那些需要在Bean实例化后立刻执行的操作。。但是假如多个Bean都有初始化方法,它们之间的执行顺序难以控制,除非依赖于Spring容器中Bean的依赖注入顺序。
实现InitializingBean接口

InitializingBean是Spring框架中的一个接口,它包含一个方法afterPropertiesSet()。当Spring容器完成了对一个Bean的所有必要属性的依赖注入后,假如该Bean实现了InitializingBean接口,Spring会自动调用其afterPropertiesSet()方法。
  1. @Component
  2. public class MyService implements InitializingBean {
  3.     @Autowired
  4.     private Dependency dependency;
  5.     @Override
  6.     public void afterPropertiesSet() throws Exception {
  7.         // 在所有依赖注入完成后执行的初始化逻辑
  8.         System.out.println("MyService初始化...");
  9.         // 初始化资源、设置状态或执行其他操作
  10.     }
  11.     // 其他业务方法...
  12. }
复制代码
适用场景:
afterPropertiesSet()方法会在所有属性注入完成后执行,确保Bean在使用前完成初始化。不需要额外的注解,只需实现接口就可以定义初始化逻辑。但是其要求Bean实现特定接口,增加了类的耦合度,同时也不符合Spring倡导的基于注解的编程风格。而且需要显式抛出异常。
相比较于@PostConstruct,@PostConstruct注解更具语义化且不强制类实现接口,降低了耦合度。推荐优先考虑使用@PostConstruct注解进行初始化逻辑的编写。
@EventListener注解

@EventListener 注解在Spring应用程序中定义事故监听器。通过监听 ApplicationReadyEvent事故,我们可以确保在应用程序完全启动并准备好接受请求时执行初始化逻辑。通过在监听器方法上添加 @EventListener 注解,并指定要监听的事故类型,可以在事故发生时执行相应的初始化操作。
  1. @Component
  2. public class StartupEventListener {
  3.     @EventListener(ApplicationReadyEvent.class)
  4.     public void onApplicationReadyEvent(ApplicationReadyEvent event) {
  5.         System.out.println("Spring Boot应用已启动并准备就绪,开始执行初始化操作...");
  6.         // 在这里执行需要在应用启动后进行的初始化代码
  7.     }
  8. }
复制代码
适用场景:
通过事故驱动的方式,将初始化逻辑与Bean的创建逻辑解耦开来,而且可以监听多种事故类型(例如:ContextRefreshedEvent),不仅仅是应用启动事故,还可用于其他业务场景。相比于@PostConstruct、CommandLineRunner或ApplicationRunner等机制,@EventListener监听的ApplicationReadyEvent在Spring Boot启动流程中的执行时机较晚,所有Bean都已经初始化并准备停当后才会触发。
总结

本文全面探讨了Spring Boot启动阶段执行初始化操作的几种常见方法,包括监听事故、实现接口以及使用注解等多种策略,具体如下:
每种方法均有其适用场景和优缺点,我们应根据项目需求和具体情况选择最适合的初始化方式。通过熟练掌握和机动运用这些方法,能够有效地管理和优化Spring Boot应用的启动流程,确保应用程序在启动之初即进入正常运作状态。
本文已收录于我的个人博客:码农Academy的博客,专注分享Java技能干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中心件、架构设计、口试题、程序员攻略等

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4