【问题标题】:Jms with abstract class as a MessageListener using spring?使用spring作为MessageListener的抽象类的Jms?
【发布时间】:2013-11-28 19:33:33
【问题描述】:

我需要您的帮助来确认我的设计是否正常。 让抽象类实现 MessageListener 是不是一个错误,因为我找不到任何这样做的资源。

此解决方案仅在我以编程方式设置消息侦听器时才有效,否则如果我尝试仅进行 spring 配置,spring 会抱怨该类是抽象的。

我想做的是提供一个 API 来使用每个应用程序必须使用的特定队列并实现她自己的 OnMessage 方法。

API 基本:

  • 连接到 JMS
  • 消费一条消息
  • 将json转换为抽象类中的对象,使用非抽象方法
  • 调用抽象方法

应用程序必须实现抽象方法,然后用对象做他们想做的事情。

我的解决方案:

public abstract class MyReceiver implements MessageListener {
    public void startReceiving() throws JMSException {
        context = new ClassPathXmlApplicationContext("jms-context-client.xml");
        AbstractMessageListenerContainer container = context.getBean("jmsContainer", AbstractMessageListenerContainer.class);
        container.setMessageSelector("JMSCorrelationID = '" + this.clientID + "'");
        container.setMessageListener(this); // <-- good practice ?
        container.start();
    }

    @Override
    public void onMessage(Message message) {
        // transform json data to object
        // call abstract method that the client MUST implement
        onMessageAbstract(response);
    }

    public abstract void onMessageAbstract(MyObject response);
}

弹簧配置:

<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start"
    destroy-method="stop">
    <property name="maxConnections" value="20" />
    <property name="connectionFactory" ref="connectionFactory" />
</bean>
<bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">
    <property name="brokerURL"><value><![CDATA[failover:(tcp://127.0.0.1:61616)?randomize=false&initialReconnectDelay=1000&useExponentialBackOff=false]]></value</property>
</bean>
<bean id="queueCommonMessage" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg value="foo.bar" />
</bean>
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" scope="prototype">
    <property name="connectionFactory" ref="connectionFactory" />
    <property name="destination" ref="queueCommonMessage" />
    <property name="autoStartup" value="false" />
    <property name="sessionTransacted" value="false"/>
    <property name="concurrentConsumers" value="1" />
</bean>

使用 API 的应用示例

public static void main(String[] args) throws JMSException {
        MyReceiver receiver = new MyReceiver("clientID") {
            @Override
            public void onMessageAbstract(MyObject response) {
                logger.debug("OK");
            }
        };
        receiver.startReceiving();    
    }

谢谢!

【问题讨论】:

  • 你能提供更多关于这个容器对象的信息吗?有关您的连接、会话数和您要连接的队列的详细信息?
  • ive 编辑问题,开始应用程序必须一次消费一条消息,没有并发消费者但他们将有许多应用程序使用相同的 api 并在同一个队列上消费他们特定的 clientID(请参阅setMessageSelector)

标签: java spring jms activemq abstract-class


【解决方案1】:

只要只有一个消费者,或者更准确地说,只要只有一个会话正在创建您的消费者(附加了您的消息侦听器),就不会有问题。

只要您的 MyReceiver 类是无状态的,就可以将其放在一行中,这没有问题,并且对于从同一队列消费的不同应用程序来说可以正常工作。

当您的 MyReceiver 类具有某种状态时,就会出现问题。例如,假设您有一个计数变量,每次您收到消息时都会递增以跟踪收到的消息总数。现在如果你说

container.setMessageListener(this);

对于从单个连接的同一会话创建的两个接收器,它们将共享您的 MyReceiver 类的实例,从而导致竞争条件。

我在JMS代码中看到的一般是

container.setMessageListener(new customMessageListener());

甚至是内部匿名类。

但是根据您的要求,您的设计看起来不错。无需创建额外的对象。

只是为了记录,虽然两个或多个接收者同时从一个队列接收消息,但消息可能会发送到任何接收者。

当你说消费一条消息时我也听不懂。

如果您使用的是异步接收。在关闭连接之前,您不能保证只会收到一条消息。如果您的应用程序希望一次只接收一条消息,请使用 receiver.receive()(同步/阻塞接收)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-13
    • 2013-06-20
    • 2010-12-07
    • 1970-01-01
    • 2014-10-23
    • 1970-01-01
    • 2010-11-18
    • 2016-02-01
    相关资源
    最近更新 更多