Spring boot 具有持久共享订阅的Artemis JUnit

Spring boot 具有持久共享订阅的Artemis JUnit,spring-boot,activemq-artemis,Spring Boot,Activemq Artemis,我使用的是artemisjunit依赖项 testImplementation("org.apache.activemq:artemis-junit") 使用Spring Boot 2+,我有两个JMS侦听器,配置如下: destination = "my.topic" clientId = "sharedApp1" subscription = "mySharedSub" durable = "tru

我使用的是
artemisjunit
依赖项

testImplementation("org.apache.activemq:artemis-junit")
使用Spring Boot 2+,我有两个JMS侦听器,配置如下:

destination = "my.topic"
clientId = "sharedApp1" 
subscription = "mySharedSub"
durable = "true"
shared = "true"
我想验证共享订阅是否有效,但当我运行JUnit测试时,会抛出第二次侦听

ActiveMQDuplicateMetaDataException[errorType=DUPLICATE_METADATA message=AMQ229035: Metadata jms-client-id=sharedApp1 had been set already]
堆栈跟踪:

javax.jms.JMSException: Failed to create session factory
at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:886) ~[artemis-jms-client-2.13.0.jar:2.13.0]
at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:299) ~[artemis-jms-client-2.13.0.jar:2.13.0]
at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:294) ~[artemis-jms-client-2.13.0.jar:2.13.0]
at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:196) ~[spring-jms-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.jms.listener.AbstractJmsListeningContainer.createSharedConnection(AbstractJmsListeningContainer.java:412) ~[spring-jms-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.jms.listener.AbstractJmsListeningContainer.establishSharedConnection(AbstractJmsListeningContainer.java:380) ~[spring-jms-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer.establishSharedConnection(DefaultMessageListenerContainer.java:818) ~[spring-jms-5.2.7.RELEASE.jar:5.2.7.RELEASE]

这是我在同一个JVM中运行时设计的(开发人员帮助)吗?还是我做错了什么?

这个错误是故意的。使用同一客户机ID的多个并发JMS客户机违反了JMS规范。JMS 2规范第6.1.2节规定:

客户端标识符的目的是将连接及其对象与提供者代表客户端维护的状态相关联。根据定义,由客户端标识符标识的客户端状态一次只能由一个客户端“使用”。JMS提供程序必须防止并发执行的客户端使用它

请记住,客户机ID对于JMS 2共享持久订阅是可选的。JMS 2规范第4.2.2节规定:

共享持久订阅通过名称和可选的 客户端标识符,并且可能具有多个消费对象 来自它的消息


这个错误是故意造成的。使用同一客户机ID的多个并发JMS客户机违反了JMS规范。JMS 2规范第6.1.2节规定:

客户端标识符的目的是将连接及其对象与提供者代表客户端维护的状态相关联。根据定义,由客户端标识符标识的客户端状态一次只能由一个客户端“使用”。JMS提供程序必须防止并发执行的客户端使用它

请记住,客户机ID对于JMS 2共享持久订阅是可选的。JMS 2规范第4.2.2节规定:

共享持久订阅通过名称和可选的 客户端标识符,并且可能具有多个消费对象 来自它的消息


在我看来,您正在同一个JVM中运行测试,但由于以下验证(org.apache.activemq.artemis.jms.client.ActiveMQConnection),因此无法运行该测试:

private void validateClientID(ClientSession validatesesession,String clientID)
引发InvalidClientIndexception,ActiveMQException{
试一试{
validateSession.addUniqueMetaData(JMS_会话_客户端_ID_属性,clientID);
}捕获(ActiveMQE异常){
if(e.getType()==ActiveMQExceptionType.DUPLICATE\u元数据){
抛出新的InvalidClientIndexception(“clientID=“+clientID+”已设置到另一个连接中”);
}否则{
投掷e;
}
}
}

在我看来,您正在同一个JVM中运行测试,但由于以下验证(org.apache.activemq.artemis.jms.client.ActiveMQConnection),因此无法运行该测试:

private void validateClientID(ClientSession validatesesession,String clientID)
引发InvalidClientIndexception,ActiveMQException{
试一试{
validateSession.addUniqueMetaData(JMS_会话_客户端_ID_属性,clientID);
}捕获(ActiveMQE异常){
if(e.getType()==ActiveMQExceptionType.DUPLICATE\u元数据){
抛出新的InvalidClientIndexception(“clientID=“+clientID+”已设置到另一个连接中”);
}否则{
投掷e;
}
}
}

谢谢您的回答,但我正在看您在哪里引用了以下内容:规范在第8.3.4节中对共享持久订阅说了相同的基本内容:共享持久订阅由客户端指定的名称和客户端标识符(如果设置)标识。如果客户端标识符是在首次创建共享持久订阅时设置的,则随后希望在该共享持久订阅上创建使用者的客户端必须使用相同的客户端标识符。因此,在删除clientId后,测试现在是成功的,但我认为根据规范,应该允许我所做的操作。然而,不使用clientId似乎更通用,因为它甚至可以由不同的应用程序(即不同的clientId)共享。但在我将答案标记为解决方案之前,请澄清这一点。谢谢,贾斯汀。事实上,规范不允许你这么做。关于这一点,我已经参考规范的适用部分澄清了我的答案。我在您链接的另一个答案中引用的规范中的一位只是说明,如果您在创建订阅时设置了客户端ID,那么您需要在稍后重新连接订阅时使用相同的客户端ID。这并不是说多个消费者可以使用同一个客户ID。谢谢你的回答,但我看到的是您引用以下内容的地方:规范在第8.3.4节中对共享持久订阅说了相同的基本内容:共享持久订阅由客户端指定的名称和客户端标识符(如果设置)标识。如果客户端标识符是在首次创建共享持久订阅时设置的,则随后希望在该共享持久订阅上创建使用者的客户端必须使用相同的客户端标识符。因此,在删除clientId后,测试现在是成功的,但我认为根据规范,应该允许我所做的操作。然而,不使用clientId似乎更通用,因为它甚至可以由不同的应用程序(即不同的clientId)共享。但在我将答案标记为解决方案之前,请澄清这一点。谢谢,贾斯汀。事实上,规范不允许你这么做。关于这一点,我已经参考规范的适用部分澄清了我的答案。我在您链接的另一个答案中引用的规范中的一位只是说明,如果您在创建订阅时设置了客户端ID,那么您需要在稍后重新连接订阅时使用相同的客户端ID。不是这么说的