【问题标题】:Unable to intercept ApplicationEnvironmentPreparedEvent in Spring Boot在 Spring Boot 中无法拦截 ApplicationEnvironmentPreparedEvent
【发布时间】:2018-02-17 01:54:37
【问题描述】:

我需要以编程方式设置一些系统属性,我认为最好的方法是在 ApplicationEnvironmentPreparedEvent 被拦截后在事件侦听器中执行此操作。 但问题是我无法在侦听器中捕捉到该事件。

@Component
public class AppListener {

    @EventListener
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory", MyThreadFactory.class.getName());
        }
    }

}

我做错了什么以及为什么我无法捕捉到该事件?

【问题讨论】:

    标签: spring-boot


    【解决方案1】:

    来自Spring Boot documentation

    一些事件实际上是在 ApplicationContext 被触发之前触发的 已创建,因此您无法将侦听器注册为@Bean。你 可以使用 SpringApplication.addListeners(...​) 方法注册它们 或 SpringApplicationBuilder.listeners(...​) 方法。

    来自Spring documentation(此为 5.1.7 版):

    @EventListener 注解的处理是通过内部执行的 自动注册的 EventListenerMethodProcessor bean 使用 Java 配置或手动通过 或元素时 使用 XML 配置。

    所以 ApplicationEnvironmentPreparedEvent(以及所有 Spring Boot 应用程序事件)发生在上下文和 bean 创建之前,并且 @EventListener 由 bean 控制,因此此时无法拾取 @EventListener 注解。您必须专门创建一个侦听器类并显式添加它以捕获此事件(或在 bean 创建之前发生的任何事件)。

    你的班级:

    public class AppListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>
    {
        @Override
        public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event)
        {
            System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory",
                    MyThreadFactory.class.getName());
        }
    }
    

    ...以及相关的 SpringApplicationBuilder 代码:

    ConfigurableApplicationContext context = new SpringApplicationBuilder(Launcher.class)
                .listeners(new AppListener()).run();
    

    【讨论】:

    • 我有这个设置,但spring.jpadatasource 确实有问题。当我使用嵌入式 tomcat 运行应用程序时,侦听器按预期工作,并且从 aws 填充属性但是当我将战争部署到 tomcat 时,它不会调用此侦听器,而是直接进入上下文初始化,然后datasource,并且由于未填充数据源属性,因此我在 jpa 初始化步骤中遇到异常。这个监听器和tomcat有什么问题?
    【解决方案2】:

    您需要专门为此事件实现ApplicationListener接口

    @Component
    public class AppListener implements ApplicationListener<ApplicationEvent> {
    
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            if (event instanceof ApplicationEnvironmentPreparedEvent) {
                System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory", MyThreadFactory.class.getName());
            }
    
        }
    }
    

    【讨论】:

    • @Compoent 创建 bean,它肯定在 IOC 中管理,而不是在它之前。
    猜你喜欢
    • 2018-08-09
    • 2017-02-19
    • 2021-03-27
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    • 2020-01-21
    • 2018-10-29
    相关资源
    最近更新 更多