java - 监听器未收到 ApplicationPreparedEvent

标签 java spring-boot

我有一个 Spring Boot 1.5.4 应用程序,它在启动时注册一个日志附加程序,这要归功于监听器,并且它可以与此处解释的解决方案一起使用 register custom log appender in spring boot starter 。监听器是我编写的启动器的一部分,并且我的带有 @EnableAutoConfiguration 的应用程序按预期工作。

我有 2 个其他应用程序使用相同的 Spring Boot 版本,我想为其使用相同的启动器。我相信它们与工作应用程序具有或多或少相同的配置,但 onApplicationEvent 方法永远不会被调用,因此我的日志附加程序未注册。下面是我的配置+监听器类。

我在supportsEventType方法中放置了一个断点,对于传递到那里的所有事件,没有一个像我的第一个应用程序中那样属于ApplicationPreparedEvent类型。

@Configuration
@EnableConfigurationProperties(MetricProperties.class)
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class MetricsAutoConfiguration implements GenericApplicationListener {

private final MetricProperties metricProperties;
private boolean addedCustomAppender = false;

public MetricsAutoConfiguration(MetricProperties metricProperties) {
    this.metricProperties = metricProperties;
}


@Bean
@ConditionalOnProperty(name = "metrics.enabled", havingValue = "true")
public EventsPublisher metricPublisher() {
    metricProperties.validate();
    return new EventsPublisher(metricProperties);
}



@Override

public void onApplicationEvent(ApplicationEvent event) {
    if (metricProperties.isEnabled() && !addedCustomAppender) {

        ApplicationPreparedEvent applicationEvent = (ApplicationPreparedEvent) event;
        EventsPublisher eventPublisher = applicationEvent.getApplicationContext().getBean(EventsPublisher.class);

    //register the log appender
    // removed for brevity

        addedCustomAppender = true;
    }
}


@Override
public int getOrder() {
    // this must be higher than LoggingApplicationListener.DEFAULT_ORDER
    return Ordered.HIGHEST_PRECEDENCE + 21;
}

@Override
public boolean supportsEventType(ResolvableType eventType) {

    return  ApplicationPreparedEvent.class.isAssignableFrom(eventType.getRawClass());
}

@Override
public boolean supportsSourceType(Class<?> sourceType) {
    return true;
}

}

在它工作的应用程序中,我看到构建了 3 个 ApplicationPreparedEvent,并且supportsEventsType 返回 true 两次(并且 onApplicationEvent 被调用两次,使用相同的事件):这发生在第 3 个 ApplicationPreparedEvent 构建之后,而不是之前。

应用程序注释是:

@SpringBootApplication
@EnableZuulProxy
@EnableBinding(OutPutChannel.class)
@EnableAutoConfiguration(exclude = MetricsDropwizardAutoConfiguration.class)
@IntegrationComponentScan

对于它不起作用的其他应用程序,我观察到在启动时仅构建了 1 个 ApplicationPreparedEvent 并且它不会触发监听器,因为调用了supportsEventsType但从未返回 true :

  • 对于第一个应用程序,它依次被调用:

    • org.springframework.boot.builder.ParentContextApplicationContextInitializer$ParentContextAvailableEvent(两次)
    • org.springframework.context.event.ContextRefreshedEvent(两次)
    • org.springframework.boot.context.event.ApplicationReadyEvent(两次)

应用程序注释是:

@SpringBootApplication
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,
    DataSourceTransactionManagerAutoConfiguration.class,
    HibernateJpaAutoConfiguration.class,
    MetricsDropwizardAutoConfiguration.class,
    JestAutoConfiguration.class})
  • 对于第二个应用程序:
    • org.springframework.context.event.ContextRefreshedEvent(两次)
    • org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent(两次)
    • org.springframework.boot.context.event.ApplicationReadyEvent(两次)

带有注释:

@SpringBootApplication
@EnableAutoConfiguration(exclude = JestAutoConfiguration.class)

对于这两种情况,都没有监听器“测试”ApplicationPreparedEvent 的痕迹...

有什么提示吗?我很困惑……

谢谢

最佳答案

在逐一删除/添加依赖项并每次进行比较后,我发现了它起作用(或不起作用)的原因,尽管我还不明白为什么......

为了让我的应用程序正确注册监听器,我需要依赖于

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
    </dependency> 

这没有多大意义,但是其中有一些东西很早就生成了 ApplicationPreparedEvent, Spring 横幅显示在日志中。在横幅显示和日​​志行显示

后构建第二个事件
The following profiles are active: XXXX

通过该配置,我可以看到我的监听器接收第二个事件并进行配置。

如果我删除对 spring-cloud-starter-feign 的依赖,则在横幅显示后(之前什么也没有),只会构建一个 ApplicationPreparedEvent,并且我的监听器永远不会收到它。

<小时/>

深入挖掘依赖关系树后,我将其范围缩小到 spring-cloud-context (我使用 1.2.2.RELEASE)。那里有一些东西会触发很早的 ApplicationPreparedEvent ,使我的监听器能够注册。我什至排除了它必须确定的唯一依赖项:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-context</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-crypto</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

如果有人有更多这方面的信息或更好的方法来实现这一点,请随时发表评论

关于java - 监听器未收到 ApplicationPreparedEvent,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45845970/

相关文章:

java - 如何在java中使用@Transactional

java - 通过 Intent 的对象数组列表

java - 如何获取 GMT + 2 的时间并将其放入微调器中的 24 小时内项目中(仅限小时和分钟)?

java - 没有持久化或数据库表的 Spring Boot 实体

spring - org.apache.kafka.common.errors.RecordTooLargeException : The request included a message larger than the max message size the server will accept 错误

java - 是否可以使用Java在cmd中打印下标数字?

java - SPRING beans 中的条件 "ref"

java - 如何在 Spring Boot 中通过 websocket 代理按照提交顺序发送消息?

java - Spring 启动 : How can I perform an integration test with real dependencies?

tomcat - 如何在Spring Boot中配置Tomcat关闭端口?