在Spring中,当我编写一个EventHandler时,可以设置一个 conditon ,以过滤出不感兴趣的事件,如下所示:
// I use lombok
public class TopicEvent extends ApplicationEvent {
@Getter @Setter private String topic;
@Getter @Setter private PayloadObject payload;
}
...
@EventListener(condition = "#event.topic eq \"ecology\"")
public void onEcologyTopicEvent(TopicEvent e) {
...
}
哪个已经很好了。但是它没有什么好处
@EventListener
public void onEcologyTopicEvent(TopicEvent e) {
if (!e.getTopic().equals("ecology") { return; }
...
}
我想为TopicEvent的用户提供一个注释
@TopicEventListener(topic = "ecology")
public void onEcologyTopicEvent(TopicEvent e) {
...
}
我对此有三个想法:
1: Spring提供了综合的注释和@AliasFor。也许可以使用
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@EventListener
public @interface TopicEventListner {
@AliasFor(annotation = EventListener.class, /* can I tweak topic to the string #event.topic eq $topic? */)
String topic;
}
2: (似乎更合理)我可以注册一些基础结构组件,也许是自定义的ApplicationEventMulticaster
还是在运行时向EventListener添加过滤器?如果是这样,那么从哪里开始是一个好地方,即哪个是我要分别在 where?中注册的类/组件,我应该在哪里实现?迷上了吗?
3 :在编译时将@TopicEventListener(topic = "ecology")
替换为@EventListener(condition = "#event.topic eq \"ecology\"")
。但是这种方法似乎...可能有点过大了,我对这类事情没有丝毫的线索,并希望它非常复杂。
...但是这可能是我用C ++(带有宏)解决它的方式
答案 0 :(得分:1)
如何定义@EcologyTopicEventListener
?
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@EventListener(condition = "#event.topic eq ecology")
public @interface EcologyTopicEventListener {
}
如果您有预定义的主题列表,则此方法比@TopicEventListener(topic="ecology")
更好,因为它消除了“生态”中可能出现的问题
如果您在编译时不知道此列表,则很可能无法采用所介绍的第一种方法。
在这种情况下,如果要在运行时定义Bean(在应用程序上下文启动期间更为精确),则可以使用Bean工厂后处理器。简而言之,它们允许以动态方式将bean定义注册到应用程序上下文中。 因此,您可以自己创建侦听器bean,甚至可以动态生成它们。
对于第三种方法,如果您问我,我也认为这是一个过大的杀手:
答案 1 :(得分:0)
由于Mark Bramnik的想法,我草拟了此解决方案:
注释不继承@EventListener
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyEventAnnotation
{
String topic() default "";
}
相反,我使用BeanPostProcessor
和ApplicationContext
创建ApplicationListeners
并为创建的每个Bean添加它们:
@Component
public class MyEventAnnotationBeanPostProcessor implements BeanPostProcessor
{
private static Logger logger = LoggerFactory.getLogger(MyEventAnnotationBeanPostProcessor.class);
@Autowired
AbstractApplicationContext ctx;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
for (Method method: bean.getClass().getMethods()) {
if (method.isAnnotationPresent(MyEventAnnotation.class)) {
MyEventAnnotation annotation = method.getAnnotation(MyEventAnnotation.class);
ctx.addApplicationListener(createApplicationListener(method, bean, annotation.topic()));
}
}
return bean;
}
private ApplicationListener<MyEvent> createApplicationListener(Method m, Object bean, String topic) {
return (MyEvent e) -> {
if (topic.equals("") || e.getTopic().equals(topic)) { // Filter here!
try {
m.invoke(bean, e);
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (InvocationTargetException e1) {
e1.printStackTrace();
}
}
};
}
}
这只是该想法的粗略概图,可能包含不安全的操作。我只是Java的初学者,所以如果您复制此代码,请不要怪我。但是随时建议修复方法:D