2014-06-17 24 views
0

我正在努力与jax-ws和自定义soapHandler。jax-ws soaphandler线程安全

我需要把一个上下文调用参数(即userID),并获得它在一个CustomHandler用于审计目的。

我试过RequestContext的方式,但由于isshared的溶液不是线程安全的所有请求地图:

客户端的方法调用把一些参数要求方面:

.... 
Map<String, Object> requestContext = provider.getRequestContext(); 
requestContext.put("userID", userId); 

处理器

@Override 
    public boolean handleMessage(SOAPMessageContext context) { 
     String userId = (String) context.get("userID); 

     return true; 
    } 

由于实例上下文是唯一的,因此这不是线程安全的。

于是,我就添加上下文参数在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); 
      } 
     } 

    } 

所以我修改了SOAP处理程序如下:

public class DataPowerSOAPHandler implements SOAPHandler<SOAPMessageContext> { 

     private String multichannelId; 

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

     return true; 
    } 

这样,我创建一个自定义SoapHandler实例每个客户端请求。

我认为是线程安全的这样,那让我觉得在客户端调用的添加/删除HandlerChain的唯一的事情....

什么建议吗?

+0

我用同一个问题的本地线程。 –

回答

1

由于消息上下文的方式不是线程安全的,我使用了标头方式。

所以我把所述公共属性在消息上下文(每个WS客户端呼叫之间共享)

Map<String, Object> requestContext = provider.getRequestContext(); 
requestContext.put(MESSAGE_CONTEXT_KEY, new SetefiMasterpassDataPowerRequest()); 

我使用绑定提供的向下转换到参考把上下文属性在每一个WS客户端呼叫执行:

.... 
WSBindingProvider provider = (WSBindingProvider) userWalletService; 
provider.setOutboundHeaders(Headers.create(new QName(MULTICHANNEL_ID_KEY), multichannelId)); 
... 

然后在处理程序中,我以2种不同的方式获得属性;从消息上下文:

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); 
} 

这是我找到解决问题的最佳途径。

0

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

然而,MessageContext设计意图本身是由具有每消息的MessageContext实例传递给每个处理程序中提供跨在单个消息处理的持续时间的松耦合的方式处理程序链线程安全连锁,链条。

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

+0

正如我所说,在我的皮肤上测试MessageContext的方式不是线程安全的。如果你在你的ws客户端中放置一个属性,并将它放到你的处理程序中,则每个不同的方法调用都会共享相同的消息上下文和相同的地图 –