记录 ApplicationEventPublisher.publishEvent() 调用

Log ApplicationEventPublisher.publishEvent() calls

我有一个 Spring Boot 2.2 应用程序,它在不同的包中发布和使用 spring 应用程序事件。现在我想在每次 ApplicationEventPublisher.publishEvent().

发布事件时记录

一个解决方案可能是编写我自己的事件发布者,例如:

public class LoggableApplicationEventPublisher implements ApplicationEventPublisher {

    private final ApplicationEventPublisher eventPublisher;
    private final Logger logger;

    public ApplicationEventLogger(ApplicationEventPublisher eventPublisher, Logger logger) {

        this.eventPublisher = eventPublisher;
        this.logger = logger;
    }


    @Override
    public void publishEvent(ApplicationEvent event) {

        eventPublisher.publishEvent(event);
        logger.info("--> Emitting {}", event);
    }
}

另一种解决方案可能是使用面向方面的编程并编写一个在每次 publishEvent() 被触发时触发的方面:

@Aspect
@Component
public class EventPublishAspect {

    private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

    @Pointcut("execution(* org.springframework.context.ApplicationEventPublisher.*(..))")
    public void logPublishEvent() {
    }


    @After("logPublishEvent()")
    public void log(JoinPoint point) {

        Object[] lArgs = point.getArgs();
        LOG.info("Triggered", lArgs[0]);
    }
}

我已经正确设置了所有内容(以及依赖项)并且这个示例适用于其他切入点(例如调用我的服务的特定方法)。

但是,此方面不适用于 ApplicationEventPublisher-接口声明的切入点。你知道为什么不吗?好像spring boot injects AbstractApplicationContext on runtime,其实就是实现了这个接口

不需要方面的解决方案(并且启动时间更快?)

    @Primary
    @Bean
    DelegatingApplicationEventPublisher applicationEventPublisher(ApplicationContext applicationContext) {
        new DelegatingApplicationEventPublisher(applicationContext)
    }
@Slf4j
@RequiredArgsConstructor
public class DelegatingApplicationEventPublisher implements ApplicationEventPublisher {

    private final ApplicationContext context;

    @Override
    public void publishEvent(ApplicationEvent event) {
        logEvent(event);
        context.publishEvent(event);
    }

    @Override
    public void publishEvent(Object event) {
        logEvent(event);
        context.publishEvent(event);
    }

    private void logEvent(Object event) {
        if (event instanceof PayloadApplicationEvent payloadApplicationEvent) {
            log.debug(markers("eventName", payloadApplicationEvent.getPayload().getClass(), "event", payloadApplicationEvent.getPayload()), "publishing...");
        } else {
            log.debug(markers("eventName", event.getClass(), "event", event), "publishing ...");
        }
    }

}