Spring Boot如何在项目启动成功后执行一段初始化逻辑


背景说明

在我们使用Spring Boot进行项目开发时,偶尔会遇到在Spring Boot项目启动完成后需要执行一些初始化的逻辑,比如缓存预加载,数据库初始化等。 那么这种需求我们需要怎么实现呢?本文将提供3种方法供大家参考。


一、入门级:启动main方法中添加初始化逻辑

在Spring Boot的main入口启动方法中,执行SpringApplication.run(LimitApplication.class, args)是可以返回ApplicationContext对象的,我们可以从ApplicationContext中获取指定的bean对象,执行初始化逻辑。

@SpringBootApplication(scanBasePackages = {
    
    "com.laowan.limit"})
public class LimitApplication {
    
    

    public static void main(String[] args){
    
    
        //启动的run方法
        ApplicationContext context =  SpringApplication.run(LimitApplication.class, args);

        //启动执行操作:从context中获取指定的bean,调度初始化逻辑
        AService aService = (AService)context.getBean("AServiceImpl");
        aService.preLoadCache();
    }

}

初始化逻辑:

@Service
public class AServiceImpl implements AService {
    
    
    @Override
    public void preLoadCache(){
    
    
        System.out.println("应用启动完成:可以执行缓存预加载操作");
    }
}

二、黄金级:实现ApplicationRunner或CommandLineRunner接口

在Spring Boot框架中,给我们提供了ApplicationRunner和CommandLineRunner接口来帮助我们解决项目启动后的初始化资源操作。
如果有多个ApplicationRunner、CommandLineRunner的实现类,可以通过@Order注解进行排序,参数值越小越早执行。

实现CommandLineRunner接口:

@Order(1)
@Component
@Slf4j
public class CommandLineRunnerImpl implements CommandLineRunner {
    
    
    @Override
    public void run(String... args) throws Exception {
    
    
        System.out.println("应用启动完成:执行CommandLineRunner方法完成资源初始化");
    }
}

实现ApplicationRunner接口:

@Order(2)
@Component
@Slf4j
public class ApplicationRunnerImpl implements ApplicationRunner {
    
    

    @Override
    public void run(ApplicationArguments args) throws Exception {
    
    
        System.out.println("应用启动完成:执行ApplicationRunner方法完成资源初始化");
    }
}

启动方法:

@SpringBootApplication(scanBasePackages = {
    
    "com.laowan.limit"})
public class LimitApplication {
    
    
    public static void main(String[] args){
    
    
        SpringApplication.run(LimitApplication.class, args);
    }
}

执行结果:

2023-06-01 10:50:20.158  INFO 24785 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-06-01 10:50:20.230  INFO 24785 --- [           main] com.laowan.limit.LimitApplication        : Started LimitApplication in 2.454 seconds (JVM running for 2.891)
应用启动完成:执行CommandLineRunner方法完成资源初始化
应用启动完成:执行ApplicationRunner方法完成资源初始化

源码分析:
在SpringApplication的run方法中,有这么一段核心代码

public ConfigurableApplicationContext run(String... args) {
    
    
                ……
try {
    
    
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);

            //通知所有监听器:spring boot已经启动完成
            listeners.started(context);
            //调用所有Runner方法,即CommandLineRunner和ApplicationRunner
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
    
    
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }
           ……  
  }      

三、大神级:ApplicationListener监听启动完成事件

通过源码,我们发现在Spring Boot启动过程中,框架内部定义了很多事件SpringApplicationEvent,用来通知SpringApplicationRunListener监听器,以针对各种事件执行对应的逻辑处理。而Spring Boot启动完成的事件对应的是ApplicationStartedEvent,我们可以通过自定义监听器来监听ApplicationStartedEvent事件,然后执行初始化资源的相关操作。

@Component
public class StartedEventListener implements ApplicationListener<ApplicationStartedEvent> {
    
    
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
    
    
        System.out.println("应用启动完成,通知监听器执行缓存预加载操作");
    }
}

猜你喜欢

转载自blog.csdn.net/w1014074794/article/details/130972183