学习如何进入应用程序引导生命周期并在Spring Boot启动时执行代码


1. Bean初始化时执行方法

Spring启动您的应用程序后,运行某些逻辑的最简单方法是将代码作为所选bean引导过程的一部分执行。

你要做什么

@PostConstruct批注的方法中即可。 从理论上讲,您可以使用构造函数代替单独的方法,但是将对象的构造与其实际职责分开是一种很好的做法。

@Component
class AppInitializator {

    private static final Logger log = LoggerFactory.getLogger(AppInitializator.class);

    @PostConstruct
    private void init() {
        log.info("AppInitializator initialization logic ...");
        // ...
    }

}

如果您使用应用程序上下文的延迟初始化(例如, 加快Spring Boot的启动速度 ),则应从此机制中排除具有初始化逻辑的bean。 我已经描述了当整个Spring上下文使用延迟加载时如何使用@Lazy批注快速创建bean 。

@PostConstruct批注创建方法。 不要忘记,主类也是由框架管理的组件。

@SpringBootApplication
public class InitDemoApplication {

    // ...

    @PostConstruct
    private void init() {
        log.info("InitDemoApplication initialization logic ...");
        // ...
    }

}

但是,此解决方案似乎是一种解决方法,而不是真正的解决方案。 您可以以非常有限的方式控制Spring框架创建应用程序Bean的顺序。 如果我们想在创建所有bean之前或者甚至在框架启动之前运行初始化逻辑,我们需要找到更好的方法。

2. Spring Boot启动挂钩

使用Spring Boot创建的应用程序的美妙之处在于,运行它们唯一需要的就是Java Runtime Environment和命令行界面。 无需外部工具或应用程序。 它像常规的Java SE程序一样运行。

与每个Java程序一样,您可以在输入应用程序类的static主方法中开始执行此类应用程序。 这就是您可以挂入Spring Boot初始化过程的关键所在。

创建Spring Boot钩子

首先在您的main方法中更改代码,以提取启动钩子到单独方法的附加内容。 您应该在启动应用程序之前添加Spring Boot挂钩。

public static void main(String[] args) {
    SpringApplication application = new SpringApplication(InitDemoApplication.class);
    addInitHooks(application);
    application.run(args);
}

static void addInitHooks(SpringApplication application) {
    // TBD …
}

当Spring Boot应用程序启动时,它将在引导过程的各个步骤上发布几个事件。 SpringApplication类的API公开了一个方法,我们可以使用该方法为这些事件添加侦听器。

这是一个示例,该示例在Spring上下文开始创建bean之前对发布的事件运行启动方法:

static void addInitHooks(SpringApplication application) {
   application.addListeners((ApplicationListener<ApplicationEnvironmentPreparedEvent>) event -> {
       String version = event.getEnvironment().getProperty("java.runtime.version");
       log.info("Running with Java {}", version);
   });
}

活动类型

根据事件类型 ,Spring传递给侦听器的对象可能使您可以访问一些有用的操作。 在前面的示例中,我们读取了一些环境属性,但也可以根据需要对其进行修改。

这是可能的事件的列表,按Spring Boot在启动时发布事件的顺序排序:

  • ApplicationStartingEvent
  • ApplicationEnvironmentPreparedEvent
  • ApplicationContextInitializedEvent
  • ApplicationPreparedEvent
  • ApplicationStartedEvent
  • ApplicationReadyEvent

我不想重复事件的文档,因此,如果您对事件描述感兴趣,就应该检查一下。 也有ApplicationFailedEvent,但仅在框架无法启动您的应用程序时才发布。

最重要的事件ApplicationEnvironmentPreparedEvent 。 在Spring Boot启动的这一刻,还没有创建bean,但是您可以访问整个应用程序配置。 通常,这是运行一些自定义启动代码的最佳时机。

3.在没有嵌入式Tomcat的情况下在启动时运行代码

尽管Spring Boot设计人员在创建框架时就考虑了构建胖JAR的问题,但一些开发人员仍将Spring Boot应用程序部署到常规的servlet容器(例如Tomcat)。 如果是这种情况,那么如果没有其他步骤,上一段中的解决方案将无法工作。

如果将应用程序部署为常规WAR文件 ,则可能已经具有SpringBootServlerInitializator的自定义实现。 您只需稍微扩展它,并在应用程序构建过程中添加初始化钩子即可。

addInitHooks()方法。

public class InitDemoWarInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        InitDemoApplication.addInitHooks(builder.application());
        return builder.sources(InitDemoApplication.class);
    }

}

结论

简而言之,在Spring Boot启动时有两个主要选项来运行代码。 最简单的方法是初始化一个特定的bean。 对于更全球化的情况,该框架具有专用的解决方案,可以使用事件监听器进入其生命周期。 我们学习了如何实现和设置此类侦听器。

希望您觉得该帖子对您有所帮助。 您可以在我的Github存储库中找到可以正常运行的演示 。 我很高兴看到您对需要自定义钩子的用例的评论。 那应该使阅读有趣。

https://www.javacodegeeks.com/2018/11/running-code-spring-boot-startup.html