2014-06-17 21 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客戶端中放置一個屬性,並將它放到你的處理程序中,則每個不同的方法調用都會共享相同的消息上下文和相同的地圖 –