【问题标题】:Listener not receiving ApplicationPreparedEvent侦听器未收到 ApplicationPreparedEvent
【发布时间】:2018-02-01 09:54:15
【问题描述】:

我有一个 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 都没有踪迹...

有什么提示吗?我很纳闷……

谢谢

【问题讨论】:

    标签: java spring-boot


    【解决方案1】:

    在逐个删除/添加依赖项并每次比较之后,我发现是什么使它工作(或不工作),即使我还不明白为什么......

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

        <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>
    

    如果有人对此有更多信息或实现此目标的更好方法,请随时发表评论

    【讨论】:

    • 如果存在上下文层次结构,则可能会发生多个 ApplicationPreparedEvent 事件。我的猜测是 spring-cloud-context 创建了一个子上下文,而您实际上是在对该事件做出反应,而不是针对您的主要上下文。
    猜你喜欢
    • 2016-11-30
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    • 2017-02-22
    相关资源
    最近更新 更多