Multithreading jax-ws-soaphandler线程安全

Multithreading jax-ws-soaphandler线程安全,multithreading,jax-ws,Multithreading,Jax Ws,我正在与jax-ws和定制soapHandler进行斗争 我需要放置一个上下文调用参数(即userID),并将其放在CustomHandler上以进行审计 我尝试了requestContext方法,但由于映射是为所有请求共享的,因此解决方案不是线程安全的: 客户端方法调用在请求上下文中放置一些参数: .... Map<String, Object> requestContext = provider.getRequestContext(); requestContext.put("u

我正在与jax-ws和定制soapHandler进行斗争

我需要放置一个上下文调用参数(即userID),并将其放在CustomHandler上以进行审计

我尝试了requestContext方法,但由于映射是为所有请求共享的,因此解决方案不是线程安全的:

客户端方法调用在请求上下文中放置一些参数:

....
Map<String, Object> requestContext = provider.getRequestContext();
requestContext.put("userID", userId);
这不是线程安全的,因为实例上下文是唯一的

因此,我尝试在CustomSoapHandler实例中添加上下文参数:

@Override
    public void deleteCard(String userId, String cardId, String multichannelId ) {

        DataPowerSOAPHandler handler = new DataPowerSOAPHandler(multichannelId);
        List<Handler> handlerChain = null;

        try {
            BindingProvider provider = (BindingProvider) userWalletService;
            handlerChain = provider.getBinding().getHandlerChain();

            logger.debug("handlerChain size {}", handlerChain.size());

            handlerChain.add(handler);
            provider.getBinding().setHandlerChain(handlerChain);

            userWalletService.deleteCard(userId, cardId);

        } finally {
            if (handlerChain != null && handlerChain.size() >0 ) {
                handlerChain.remove(handler);
            }
        }

    }
@覆盖
公共无效删除卡(字符串userId、字符串carid、字符串多通道id){
DataPowerSOAPHandler处理程序=新的DataPowerSOAPHandler(多通道ID);
列表handlerChain=null;
试一试{
BindingProvider=(BindingProvider)userWalletService;
handlerChain=provider.getBinding().getHandlerChain();
debug(“handlerChain size{}”,handlerChain.size());
handlerChain.add(handler);
provider.getBinding().setHandlerChain(handlerChain);
userWalletService.deleteCard(userId,carid);
}最后{
if(handlerChain!=null&&handlerChain.size()>0){
把手链条。移除(把手);
}
}
}
因此,我对soap处理程序进行了如下修改:

 public class DataPowerSOAPHandler implements SOAPHandler<SOAPMessageContext> {

        private String multichannelId;

@Override
    public boolean handleMessage(SOAPMessageContext context) {
        System.out.println("multichannelId");

        return true;
    }
public类DataPowerSOAPHandler实现SOAPHandler{
私有字符串多通道ID;
@凌驾
公共布尔handleMessage(SOAPMessageContext上下文){
System.out.println(“多通道ID”);
返回true;
}
通过这种方式,我为每个客户机请求创建一个自定义SoapHandler实例

我认为这样做是线程安全的,唯一让我想到的是在客户端调用中添加/删除handlerChain


有什么建议吗?

如果在处理程序实例中存储状态(例如作为实例变量),则可能会出现线程安全问题。例如,由同一处理程序实例处理的两条单独的soap消息-如果应用程序使用web服务绑定提供程序(存根)的静态实例并且它附加了一个处理程序链,这些对象实例可以用于多个web服务请求/响应

但是,其设计意图是在单个消息处理期间以松散耦合的方式跨处理程序链提供线程安全性,方法是为传递给链中每个处理程序的每条消息提供一个
MessageContext
实例


它类似于servlet世界——想想
HttpServletRequest
:如果
HttpServlet
ServletFilter
(很像JAX-WS soap处理程序)有一个实例变量,该变量在对该servlet实例的用户http请求之间共享,因此不是线程安全的。但是,两个浏览器请求始终等于传递给
service()
方法族的两个
HttpServletRequest
对象(
doGet()
,等等),因此任何用户或特定于请求的状态值都可以安全地存储为请求属性,并由其他已调度/转发的servlet或后处理筛选器读取。这就是JAX-WS处理程序的工作方式;它们是有效的筛选器。

如果将状态存储在处理程序实例中(例如,作为实例变量)您将面临线程安全问题的风险。例如,由同一处理程序实例处理的两条单独的soap消息-如果应用程序使用web服务绑定提供程序(存根)的静态实例,并且它连接了处理程序链,则这些对象实例可用于多个web服务请求/响应

但是,其设计意图是在单个消息处理期间以松散耦合的方式跨处理程序链提供线程安全性,方法是为传递给链中每个处理程序的每条消息提供一个
MessageContext
实例


它类似于servlet世界——想想
HttpServletRequest
:如果
HttpServlet
ServletFilter
(很像JAX-WS soap处理程序)有一个实例变量,该变量在对该servlet实例的用户http请求之间共享,因此不是线程安全的。但是,两个浏览器请求始终等于传递给
service()
方法族的两个
HttpServletRequest
对象(
doGet()
,等等),因此任何用户或特定于请求的状态值都可以安全地存储为请求属性,并由其他已调度/转发的servlet或后处理筛选器读取。这就是JAX-WS处理程序的工作方式;它们是有效的筛选器。

如果将状态存储在处理程序实例中(例如,作为实例变量)您将面临线程安全问题的风险。例如,由同一处理程序实例处理的两条单独的soap消息-如果应用程序使用web服务绑定提供程序(存根)的静态实例,并且它连接了处理程序链,则这些对象实例可用于多个web服务请求/响应

但是,其设计意图是在单个消息处理期间以松散耦合的方式跨处理程序链提供线程安全性,方法是为传递给链中每个处理程序的每条消息提供一个
MessageContext
实例

它类似于servlet世界——想想
HttpServletRequest
:如果
HttpServlet
ServletFilter
(很像JAX-WS soap处理程序)有一个实例变量,该变量在对该servlet实例的用户http请求之间共享,因此不是线程安全的。但是,两个浏览器请求始终等于传递给
service()
方法族的两个
HttpServletRequest
对象(
doGet()
,等等),因此任何特定于用户或请求的状态值都可以安全地存储为请求属性,并由其他已调度/转发的servlet或后处理程序读取
 public class DataPowerSOAPHandler implements SOAPHandler<SOAPMessageContext> {

        private String multichannelId;

@Override
    public boolean handleMessage(SOAPMessageContext context) {
        System.out.println("multichannelId");

        return true;
    }
Map<String, Object> requestContext = provider.getRequestContext();
requestContext.put(MESSAGE_CONTEXT_KEY, new SetefiMasterpassDataPowerRequest());
....
WSBindingProvider provider = (WSBindingProvider) userWalletService;
provider.setOutboundHeaders(Headers.create(new QName(MULTICHANNEL_ID_KEY), multichannelId));
...
DataPowerRequest dataPowerRequest = (DataPowerRequest) context.get(MESSAGE_CONTEXT_KEY);
SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
SOAPHeader envelopeHeader = envelope.getHeader();

NodeList multichannelIdNode = envelopeHeader.getElementsByTagNameNS("*", MULTICHANNEL_ID_KEY);

String multichannelId = null; 

if (multichannelIdNode != null && multichannelIdNode.item(0)!= null && multichannelIdNode.item(0).getChildNodes() != null) {
                Node item = multichannelIdNode.item(0);
                multichannelId = item.getChildNodes().item(0).getNodeValue();
                item.getParentNode().removeChild(item);
}