调用ActiveMQConnection清理和changeuserinfo是否会影响DefaultMessageListenerContainer与CACHE_CONSUMER

时间:2016-03-08 18:33:41

标签: oauth activemq spring-jms

以下是一些上下文:我已经设置了一个带有BrokerPlugin的ActiveMQBroker(版本5.13.1),它接受一个requestId(仅用于跟踪不同服务器上的请求的UUID)和OAuth令牌(更多关于下面的OAuth令牌) org.apache.activemq.command.ConnectionInfo的'username'和'password'字段分别基于this great post。在客户端/消费者方面,我使用cacheLeve = CACHE_CONSUMER将SpringMQConnection包装在Spring DefaultMessageListenerContainer(版本4.2.4-RELEASE)中(因此它还会将Session和Consumer与Connection连接在一起)。

问题是客户端的OAuth令牌每20分钟到期一次,所以我在客户端设置了ScheduledExecutorService,每18分钟刷新一次OAuth令牌。

我的问题是,如果我在客户端调度的任务调用ActiveMQConnection#cleanup()后跟ActiveMQConnection#changeUserInfo(newRequestId,newAuthToken)...那会对spring持有同一ActiveMQConnection的DefaultMessageListenerContainer产生负面影响吗?或者另一种问题,是否有一种“正确”的方式让我的客户端代码在ActiveMQConnection中设置新的“用户名”和“密码”字段而不会弄乱DefaultMessageListenerContainer中的任何内容?我特别关注任何多线程问题,因为DefaultMessageListenerContainer有几个消费者线程......而我的ScheduledExecutorService当然是运行它自己的线程来将OAuth令牌更新为ActiveMQConnection。

扩展DefaultMessageListenerContainer并将OAuth令牌的更新包装在'sharedConnectionMonitor'的同步块中是否足够,例如:以下是必要和/或充分的事情:

public class OAuthMessageListenerContainer extends DefaultMessageListenerContainer {
    public void updateOAuthToken(String requestId, String authToken) throws JMSException {
        synchronized(sharedConnectionMonitor) {
            ActiveMQConnection amqConn = (ActiveMQConnection)getSharedConnection();
            amqConn.doCleanup(true);
            amqConn.changeUserInfo(requestId, authToken);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

FWIW在这里我是如何解决这个问题的:

1)我首先必须将ActiveMQ从5.13.0升级到5.13.3,因为5.13.0在传输中断后尝试重新连接到代理时遇到了FailoverTransport的线程死锁问题,例如:网络故障,服务器重启,动物园管理员选举新的"主人"经纪人(我们在3台经纪人的服务器上使用复制的leveldb)

2)在ActiveMQ中经过线程死锁后,我意识到在ActiveMQConnection上更改用户名和密码基本上会重置整个连接...这意味着DMLC被重置...所以我创建了DMLC的子类当传输中断时,我可以从连接上的TransportListener重置...但是然后在DMLC中遇到了另一个线程死锁...并找到帮助我过去的this answer

DMLC的子类只需要这种方法:

public void restart() {
    try {
        shutdown();
        initialize();
        start();
    }
    catch (Exception e) {
        LOG.error("Could not restart DMLC", e);
    }
}

并且传输侦听器需要执行此操作:

@Override
public void transportInterrupted() {
    dmlc.restart();
}