我有两个同一类的 bean,我想分别监听一个特定于 bean 的通用事件:
public class MyBeanClass <E> {
@EventListener
public void handleEvent(E event) { ... }
}
配置:
public class MyConfig {
@Bean
public MyBeanClass<AEvent> myBeanAClass() {
return new MyBeanClass<>();
}
@Bean
public MyBeanClass<BEvent> myBeanBClass() {
return new MyBeanClass<>();
}
}
因此 bean“myBeanAClass”应监听 AEvent,而 bean“myBeanBClass”应监听 BEvent。
测试:
@Test
public void testHandleAEvent() {
AEvent event = new AEvent();
publisher.publishEvent(event);
Mockito.verify(myBeanAClass, times(1)).handleEvent(Mockito.any()); // Fail
Mockito.verify(myBeanBClass, times(0)).handleEvent(Mockito.any());
}
错误:
org.mockito.exceptions.verification.TooManyActualInvocations:
mypackage.MyBeanClass#0 bean.handleEvent(
<any>
);
Wanted 1 time:
-> at mypackage.MyTest.testHandleAEvent(MyTest.java:45)
But was 5 times:
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
最佳答案
因为Type Erasure通用类型E
在handleEvent(E event)
将替换为 Object
。替换后的类将如下所示:
public class MyBeanClass {
@EventListener
public void handleEvent(Object event) { ... }
}
这意味着此类监听器将接受来自应用程序的任何事件,甚至是由 spring 框架内部生成的事件。方法签名声明它消耗的事件类型。 EventListener documentation
解决方案 1. 为每个事件创建监听器适配器
基本通用监听器的适配器:
public class MyBeanClass <E> {
public void handleEvent(E event) {
event.toString();
}
}
public class MyBeanAClass {
private MyBeanClass<AEvent> myBeanClass;
public MyBeanAClass(MyBeanClass<AEvent> myBeanClass) {
this.myBeanClass = myBeanClass;
}
@EventListener
public void handleEvent(AEvent event) {
myBeanClass.handleEvent(event);
}
}
public class MyBeanBClass {
private MyBeanClass<BEvent> myBeanClass;
public MyBeanBClass(MyBeanClass<BEvent> myBeanClass) {
this.myBeanClass = myBeanClass;
}
@EventListener
public void handleEvent(BEvent event) {
myBeanClass.handleEvent(event);
}
}
Activity :
public class AEvent extends ApplicationEvent {
private final String message;
public AEvent(Object source, String message) {
super(source);
this.message = message;
}
}
public class BEvent extends ApplicationEvent {
private final String message;
public BEvent(Object source, String message) {
super(source);
this.message = message;
}
}
配置:
public class MyConfig {
@Bean
public MyBeanAClass myBeanAClass() {
return new MyBeanAClass(new MyBeanClass<>());
}
@Bean
public MyBeanBClass myBeanBClass() {
return new MyBeanBClass(new MyBeanClass<>());
}
}
测试:
class ApplicationTests {
@MockBean
private MyBeanAClass myBeanAClass;
@MockBean
private MyBeanBClass myBeanBClass;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Test
public void testHandleAEvent() {
AEvent event = new AEvent(this, "Message");
applicationEventPublisher.publishEvent(event);
Mockito.verify(myBeanAClass, times(1)).handleEvent(Mockito.any());
Mockito.verify(myBeanBClass, times(0)).handleEvent(Mockito.any());
}
}
解决方案 2. 通用应用程序事件
创建通用事件类型。实现org.springframework.core.ResolvableTypeProvider
在通用事件类中,然后监听器将解决它。
public class GenericSpringEvent<T> implements ResolvableTypeProvider {
private final T source;
public GenericSpringEvent(T source) {
this.source = source;
}
public T getSource() {
return source;
}
@Override
public ResolvableType getResolvableType() {
return ResolvableType.forClassWithGenerics(
getClass(),
ResolvableType.forInstance(this.source)
);
}
}
为每个事件实现通用监听器
public class GenericSpringAEventListener {
@EventListener
public void handle(GenericSpringEvent<AEvent> event) {
event.toString();
}
}
public class GenericSpringBEventListener {
@EventListener
public void handle(GenericSpringEvent<BEvent> event) {
event.toString();
}
}
配置:
public class MyConfig {
@Bean
public GenericSpringAEventListener genericSpringAEventListener() {
return new GenericSpringAEventListener();
}
@Bean
public GenericSpringBEventListener genericSpringBEventListener() {
return new GenericSpringBEventListener();
}
}
测试:
class ApplicationTests {
@MockBean
private GenericSpringAEventListener aListener;
@MockBean
private GenericSpringBEventListener bListener;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Test
public void testHandleAEvent() {
AEvent event = new AEvent(this, "Message");
GenericSpringEvent<AEvent> genericEvent = new GenericSpringEvent<>(event);
applicationEventPublisher.publishEvent(genericEvent);
Mockito.verify(aListener, times(1)).handle(Mockito.any());
Mockito.verify(bListener, times(0)).handle(Mockito.any());
}
}
关于java - Spring 通用事件的事件监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71452445/