问题描述
我有一个 Spring Boot 1.5.4 应用程序,它在启动时注册一个日志附加程序,多亏了一个监听器,它适用于这里解释的解决方案 在 spring boot starter 中注册自定义日志 appender .侦听器是我编写的 starter 的一部分,我的带有 @EnableAutoConfiguration 的应用程序按预期工作.
I have a Spring Boot 1.5.4 app that registers a log appender at startup, thanks to a listener, and it works with the solution explained here register custom log appender in spring boot starter . The listener is part of a starter that I have written, and my app with @EnableAutoConfiguration works as expected.
我有 2 个其他应用程序使用相同的 Spring Boot 版本,我想使用相同的启动器.我相信它们与工作应用程序或多或少具有相同的配置,但是 onApplicationEvent 方法永远不会被调用,因此我的日志附加程序没有注册.下面是我的配置+监听器类.
I have 2 other applications using the same Spring Boot version for which I would like to use the same starter. I believe they have more or less the same config as the working application, but the onApplicationEvent method never gets called and therefore my log appender isn’t registered. Below is my configuration + listener class .
我在 supportsEventType 方法中放置了一个断点,并且对于传递到那里的所有事件,没有一个像在我的第一个应用程序中那样属于 ApplicationPreparedEvent 类型.
I have put a breakpoint in supportsEventType method and for all the events that get passed there, none is of type ApplicationPreparedEvent like in my first app.
@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 构建之后,而不是之前.
In the application for which it works, I see that 3 ApplicationPreparedEvent are built, and supportsEventsType returns true twice (and onApplicationEvent is called twice, with the same event) : this happens after the 3rd ApplicationPreparedEvent is built, not before.
应用注释是:
@SpringBootApplication
@EnableZuulProxy
@EnableBinding(OutPutChannel.class)
@EnableAutoConfiguration(exclude = MetricsDropwizardAutoConfiguration.class)
@IntegrationComponentScan
对于它不工作的其他应用程序,我观察到只有 1 个 ApplicationPreparedEvent 在启动时被构建并且它不会触发监听器,因为 supportsEventsType 被调用但从不返回 true :
For the other applications for which it doesn’t work, I observe that only 1 ApplicationPreparedEvent is built at startup and it doesn’t trigger the listener, because supportsEventsType is called but never returns true :
对于第一个应用程序,它被连续调用:
For the first app, it’s called successively by :
- 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 被监听器测试"...
For both, not trace of ApplicationPreparedEvent being "tested" by the listener...
有什么提示吗?我很困惑……
Any hint ? I’m quite puzzled…
谢谢
推荐答案
在逐一删除/添加依赖项并每次比较后,我发现了是什么让它起作用(或不起作用),尽管我不明白为什么还...
After removing/adding dependencies one by one and comparing each time, I have found what makes it work (or not), even though I don't understand why yet...
为了让我的应用程序正确注册监听器,我需要依赖于
For my application to register the listener properly, I need to have a dependency to
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
这没有多大意义,但其中有一些东西很早就生成了 ApplicationPreparedEvent,在日志中显示 Spring 横幅之前.在横幅显示和日志行说
It doesn't make much sense, but there is something in there that generates an ApplicationPreparedEvent very early, before the Spring banner shows in the logs. A second event is built after the banner shows and the log line saying
The following profiles are active: XXXX
使用该配置,我可以看到我的侦听器接收第二个事件并进行配置.
with that config, I can see my listener receiving the second event and being configured.
如果我删除了对 spring-cloud-starter-feign 的依赖,那么只有一个 ApplicationPreparedEvent 被构建,在横幅显示之后(之前什么都没有)并且我的听众永远不会收到它.
If I remove the dependency to spring-cloud-starter-feign, then only one ApplicationPreparedEvent is built, after the banner shows (nothing before) and my listener never receives it.
在挖掘依赖树之后,我将它缩小到 spring-cloud-context(我使用 1.2.2.RELEASE).那里有一些东西会触发那个非常早的 ApplicationPreparedEvent,使我的侦听器能够被注册.我什至排除了它必须确定的唯一依赖项:
After digging down the dependency tree, I've narrowed it down to spring-cloud-context (I use 1.2.2.RELEASE). There's something in there that triggers that very early ApplicationPreparedEvent that enables my listener to be registered. I've even excluded the only dependency it has to be sure :
<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>
如果有人对此有更多信息或实现此目标的更好方法,请随时发表评论
If anyone has more informations on this or a better way to achieve this, feel free to comment
这篇关于侦听器未收到 ApplicationPreparedEvent的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!