是否可以在运行时使用 Spring 配置设置 JMS 侦听器目标
Is it possible to set a JMS listener destination at runtime with Spring configuration
我们在 Spring 应用程序中使用 ActiveMQ,我正在设置使用基于定义发送数据的 class 名称的虚拟主题的设计。所以如果我有 class
public class SomeEvent implements JmsEvent<SomeEvent> {
...
}
其中 JmsEvent
是用于将实现 class 转换为 Message
的辅助接口,我有另一个 class 将使用可配置的覆盖确定目标名称
public class DestinationNameHelper {
private Map<Class<?>, String> overrides;
...
public String getDestinationName(Class<?> type) {
return overrides.getOrDefault(type, type.getSimpleName());
}
}
这适用于 JmsTemplate
,其中为每条发送的消息传递目的地名称。我有一个 class 预置 VirtualTopic.
结果,所以如果你调用 publisher.publish(someEvent)
发送 SomeEvent
的实际目的地将是 VirtualTopic.SomeEvent
.
我想做的是为听众使用相同类型的东西,所以如果我有
public class SomeEventListener extends BaseMessageListener<SomeEvent> {
public void handleMessage(Message message) {}
}
我希望能够自动将其设置为侦听目的地 Consumer.SomeEventListener.VirtualTopic.SomeEvent
,现在正在将其手动输入到 XML 配置文件中。
让监听器 class 名称可覆盖会很好,但我至少希望通过 DestinationNameHelper
检索虚拟主题名称(即 SomeEvent
),这样监听器配置就不会如果我们覆盖 class' 目的地名称,则不必更改。
例如如果我们将 (SomeEvent.class, "OverrideName")
添加到 DestinationNameHelper
中的覆盖映射,class SomeEvent
的消息应该在
上发布
VirtualTopic.OverrideName
听者应该听
Consumer.SomeEventListener.VirtualTopic.OverrideName
我无法弄清楚在 XML 配置中执行此操作的 SPEL 咒语,并且目标是使用 JmsListenerConfigurer
使目的地名称基于 class 名称可能超出范围。
有没有办法实现我想要的配置?
[编辑]
我的配置看起来像这样:
<bean id="someEventListenerBean" class="com.example.SomeEventListener"/>
<bean id="someEventListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="com.example.SomeEventListener"/>
</constructor-arg>
<property name="messageConverter">
<null/>
</property>
</bean>
<jms:listener-container connection-factory="jmsConnectionFactory" acknowledge="transacted" concurrency="2-5">
<jms:listener destination="Consumer.SomeEventListener.VirtualTopic.Somevent" ref="testListener"/>
</jms:listener-container>
感谢贾斯汀和加里成为橡皮鸭。澄清并发布我的配置帮助我找到了答案,尽管它可能会被优化。
我修改了 Listener 接口以包含
Class<T> getEventType();
所以所有实施 classes 的人都必须 return 他们正在处理的事件的 class 类型。然后我创建了一个 class like
public class ListenerDestinationHelper {
private final DestinationHelper destinationHelper;
public ListenerDestinationHelper(DestinationHelper destinationHelper) {
this.destinationHelper = destinationHelper;
}
public <E extends JmsEvent<E>, M extends Message, T extends JmsEventListener<E, M>> String getDestinationName(T listener) {
final Class<E> eventClass = listener.getEventType();
return "Consumer." + listener.getClass().getSimpleName() + ".VirtualTopic." + destinationNameFactory.getDestinationBaseName(eventClass);
}
}
现在配置包括
<bean id="listenerDestinationHelper" class="com.example.ListenerDestinationHelper"/>
<jms:listener-container connection-factory="jmsConnectionFactory" acknowledge="transacted" concurrency="2-5">
<jms:listener destination="#{listenerDestinationHelper.getDestinationName(someEventListenerBean)}" ref="testListener"/>
</jms:listener-container>
从这里开始,为侦听器添加覆盖是微不足道的 class 简单名称
我们在 Spring 应用程序中使用 ActiveMQ,我正在设置使用基于定义发送数据的 class 名称的虚拟主题的设计。所以如果我有 class
public class SomeEvent implements JmsEvent<SomeEvent> {
...
}
其中 JmsEvent
是用于将实现 class 转换为 Message
的辅助接口,我有另一个 class 将使用可配置的覆盖确定目标名称
public class DestinationNameHelper {
private Map<Class<?>, String> overrides;
...
public String getDestinationName(Class<?> type) {
return overrides.getOrDefault(type, type.getSimpleName());
}
}
这适用于 JmsTemplate
,其中为每条发送的消息传递目的地名称。我有一个 class 预置 VirtualTopic.
结果,所以如果你调用 publisher.publish(someEvent)
发送 SomeEvent
的实际目的地将是 VirtualTopic.SomeEvent
.
我想做的是为听众使用相同类型的东西,所以如果我有
public class SomeEventListener extends BaseMessageListener<SomeEvent> {
public void handleMessage(Message message) {}
}
我希望能够自动将其设置为侦听目的地 Consumer.SomeEventListener.VirtualTopic.SomeEvent
,现在正在将其手动输入到 XML 配置文件中。
让监听器 class 名称可覆盖会很好,但我至少希望通过 DestinationNameHelper
检索虚拟主题名称(即 SomeEvent
),这样监听器配置就不会如果我们覆盖 class' 目的地名称,则不必更改。
例如如果我们将 (SomeEvent.class, "OverrideName")
添加到 DestinationNameHelper
中的覆盖映射,class SomeEvent
的消息应该在
VirtualTopic.OverrideName
听者应该听
Consumer.SomeEventListener.VirtualTopic.OverrideName
我无法弄清楚在 XML 配置中执行此操作的 SPEL 咒语,并且目标是使用 JmsListenerConfigurer
使目的地名称基于 class 名称可能超出范围。
有没有办法实现我想要的配置?
[编辑] 我的配置看起来像这样:
<bean id="someEventListenerBean" class="com.example.SomeEventListener"/>
<bean id="someEventListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="com.example.SomeEventListener"/>
</constructor-arg>
<property name="messageConverter">
<null/>
</property>
</bean>
<jms:listener-container connection-factory="jmsConnectionFactory" acknowledge="transacted" concurrency="2-5">
<jms:listener destination="Consumer.SomeEventListener.VirtualTopic.Somevent" ref="testListener"/>
</jms:listener-container>
感谢贾斯汀和加里成为橡皮鸭。澄清并发布我的配置帮助我找到了答案,尽管它可能会被优化。
我修改了 Listener 接口以包含
Class<T> getEventType();
所以所有实施 classes 的人都必须 return 他们正在处理的事件的 class 类型。然后我创建了一个 class like
public class ListenerDestinationHelper {
private final DestinationHelper destinationHelper;
public ListenerDestinationHelper(DestinationHelper destinationHelper) {
this.destinationHelper = destinationHelper;
}
public <E extends JmsEvent<E>, M extends Message, T extends JmsEventListener<E, M>> String getDestinationName(T listener) {
final Class<E> eventClass = listener.getEventType();
return "Consumer." + listener.getClass().getSimpleName() + ".VirtualTopic." + destinationNameFactory.getDestinationBaseName(eventClass);
}
}
现在配置包括
<bean id="listenerDestinationHelper" class="com.example.ListenerDestinationHelper"/>
<jms:listener-container connection-factory="jmsConnectionFactory" acknowledge="transacted" concurrency="2-5">
<jms:listener destination="#{listenerDestinationHelper.getDestinationName(someEventListenerBean)}" ref="testListener"/>
</jms:listener-container>
从这里开始,为侦听器添加覆盖是微不足道的 class 简单名称