【发布时间】:2020-01-06 14:44:37
【问题描述】:
有一个 Spring Boot 应用程序与基于 SOAP 的服务连接。我们的应用程序有一个 MQ 侦听器,它从本地队列接收消息。一旦消息从该队列中出列,它就会对服务进行 API 调用。
与基于 SOAP 的服务的所有通信都是通过 2 路 SSL 完成的。
现在我们在连接基于 SOAP 的服务时遇到了问题。在基于 SOAP 的服务端间歇性收到缺少客户端证书链错误。
在我们的 JmsConfig 类中,我们将侦听器工厂的并发设置为 10,如下所示,用于并发执行和并行处理来自队列的消息。
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(){
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
try {
factory.setConnectionFactory(cachingConnectionFactory(jmsConnectionFactoryX20()));
factory.setConcurrency("10");
} catch (JMSException e) {
e.printStackTrace();
}
return factory;
}
当我们在使用消息后进一步从 Spring Boot 应用程序调用 SOAP 服务时,大多数消息的 SOAP 服务日志中都会出现缺少客户端证书链错误。在队列中批量加载 1k 条消息并随后并发执行时,大约 850 条消息在 SOAP 服务端失败,只有 150 条通过。
只有在通过上面的代码 sn-p 以编程方式设置并发时才会出现错误。如果我注释掉 setConcurrency 调用,所有 1k 消息都会在 SOAP 服务端得到处理,而不会出现任何证书链错误。
您能否看看我们的配置,并分享一些关于并发导致此错误的原因。
ApplicationWebServiceImpl.java(从 JMS 监听器方法调用 callWebService() 方法)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.SoapMessage;
@Service
public class ApplicationWebServiceImpl implements ApplicationWebServices {
@Autowired
private WebServiceTemplate wsTemplate;
@Value("${soap.clientEndpoint}")
private String clientEndpoint;
@Value("${soap.action}")
private String soapAction;
@Override
public Object callWebService(Object request, String serviceName) throws ClientApplicationException {
return wsTemplate.marshalSendAndReceive(clientEndpoint + serviceName, request, message -> {
SoapMessage msg = (SoapMessage) message;
msg.setSoapAction(soapAction + StringUtils.capitalize(serviceName));
});
}
}
ClientApplication(Spring boot 主类)
@SpringBootApplication
@ComponentScan("com.abc.ca")
public class ClientApplication {
@Value(value = "${cert.keyStoreFileName}")
private String keyStoreFileName;
@Value(value = "${cert.trustStoreFileName}")
private String trustStoreFileName;
@Value(value = "${cert.disabledAlgorithms}")
private String disabledAlgorithms;
@PostConstruct
public void getKeyTrustStore() {
Security.setProperty("jdk.certpath.disabledAlgorithms", disabledAlgorithms);
String filePath = Thread.currentThread().getContextClassLoader().getResource(keyStoreFileName).getFile();
System.setProperty("javax.net.ssl.keyStore", filePath);
System.setProperty("javax.net.ssl.keyStorePassword", "changeme");
filePath = Thread.currentThread().getContextClassLoader().getResource(trustStoreFileName).getFile();
System.setProperty("javax.net.ssl.trustStore", filePath);
System.setProperty("javax.net.ssl.trustStorePassword", "changeme");
}
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
【问题讨论】:
-
这与 IBM MQ 有关吗?看来实际的证书问题是您的 SOAP 服务调用而不是 MQ?
-
是的,它是 IBM MQ。证书问题与 SOAP 服务调用有关。未设置并发时,SOAP 服务可以完美地处理 1k 负载。当我在 MQ 配置类中将并发设置为 10 时,对于某些消息,SOAP 服务给出缺少客户端证书链错误。
-
当您将并发设置为大于 1 时,您将在应用程序中引入并发。您的应用程序需要确保每个消费者都可以使用所需的客户端证书链。我怀疑您的变量要么超出范围要么被删除,然后才能使用它们。因此,正如@JoshMc 所暗示的那样,错误很可能在您调用 SOAP 服务的逻辑中不是并发安全的。你应该分享这个逻辑,这样我们就可以帮助确定这是否是问题所在。
-
您好,我已经分享了服务调用代码以及设置证书的类。
标签: java spring-boot concurrency ibm-mq