2012-05-15 13 views
17

डब्ल्यूएस क्लाइंट सेवा और बंदरगाह के प्रारंभ होने के बाद से उम्र शुरू होती है, मैं स्टार्टअप पर उन्हें एक बार शुरू करना चाहता हूं और बंदरगाह के उसी उदाहरण का पुन: उपयोग करना चाहता हूं। Initalization कुछ इस तरह दिखेगा:क्या यह जेएक्स-डब्ल्यूएस क्लाइंट कॉल थ्रेड सुरक्षित है?

private static RequestContext requestContext = null; 

static 
{ 
    MyService service = new MyService(); 
    MyPort myPort = service.getMyServicePort(); 

    Map<String, Object> requestContextMap = ((BindingProvider) myPort).getRequestContext(); 
    requestContextMap = ((BindingProvider)myPort).getRequestContext(); 
    requestContextMap.put(BindingProvider.USERNAME_PROPERTY, uName); 
    requestContextMap.put(BindingProvider.PASSWORD_PROPERTY, pWord); 

    rc = new RequestContext(); 
    rc.setApplication("test"); 
    rc.setUserId("test"); 
} 

मेरी कक्षा में कहीं कॉल:

myPort.someFunctionCall(requestContext, "someValue"); 

मेरा प्रश्न: इस कॉल के धागे की सुरक्षित हो जाएगा?

जॉनी

+3

पहले से ही यहाँ उत्तर दिया गया है: http://stackoverflow.com/questions/4385204/are-jax-ws-clients-thread-safe – kyiu

+0

हाय KHY

import org.apache.commons.pool2.BasePooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.apache.commons.pool2.impl.GenericObjectPool; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; class ServiceObjectPool<T> extends GenericObjectPool<T> { public ServiceObjectPool(java.util.function.Supplier<T> factory) { super(new BasePooledObjectFactory<T>() { @Override public T create() throws Exception { return factory.get(); } @Override public PooledObject<T> wrap(T obj) { return new DefaultPooledObject<>(obj); } }); } public static class PooledServiceProxy<T> implements InvocationHandler { private ServiceObjectPool<T> pool; public PooledServiceProxy(ServiceObjectPool<T> pool) { this.pool = pool; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { T t = null; try { t = this.pool.borrowObject(); return method.invoke(t, args); } finally { if (t != null) this.pool.returnObject(t); } } } @SuppressWarnings("unchecked") public T getProxy(Class<? super T> interfaceType) { PooledServiceProxy<T> handler = new PooledServiceProxy<>(this); return (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class<?>[]{interfaceType}, handler); } } 

प्रॉक्सी का उपयोग करने के लिए , आपके त्वरित उत्तर के लिए धन्यवाद। मैंने यह धागा देखा। मेरी समस्या यह है कि मैं किसी भी (सरकारी) बयान क्या threadsafe है या नहीं की कमी कर रहा हूँ (सेवा/पोर्ट/आदि।)। मेरा उपयोगकाज भी अन्य धागे से अलग है। जॉनी – user871611

+1

यहाँ एक जवाब मैं CXF वेबसाइट पर पाया: https://cwiki.apache.org/CXF/faq.html#FAQ-AreJAXWSclientproxiesthreadsafe%253F – kyiu

उत्तर

19

CXF FAQ के अनुसार:

JAX-WS ग्राहक प्रॉक्सी धागा सुरक्षित हैं?

सरकारी JAX-WS जवाब: सं JAX-WS कल्पना के अनुसार, ग्राहक प्रॉक्सी सुरक्षित सूत्र नहीं कर रहे हैं। पोर्टेबल कोड लिखने के लिए, आपको उन्हें गैर-थ्रेड सुरक्षित के रूप में व्यवहार करना चाहिए और एक्सेस सिंक्रनाइज़ करना या उदाहरणों या इसी तरह के पूल का उपयोग करना चाहिए।

सीएक्सएफ उत्तर: सीएक्सएफ प्रॉक्सी कई उपयोग मामलों के लिए थ्रेड सुरक्षित हैं। अपवाद हैं:

((BindingProvider)proxy).getRequestContext() की
  • उपयोग - प्रति JAX-WS कल्पना, अनुरोध संदर्भ उदाहरण प्रति है। इस प्रकार, सेट किए गए कुछ भी अन्य धागे पर अनुरोधों को प्रभावित करेंगे। CXF के साथ, आप कर सकते हैं: getRequestContext (करने के लिए

    ((BindingProvider)proxy).getRequestContext().put("thread.local.request.context","true"); 
    

    और भविष्य के कॉल) एक धागा स्थानीय अनुरोध संदर्भ का उपयोग करेगा। यह अनुरोध संदर्भ थ्रेडसेफ होने की अनुमति देता है। (नोट: प्रतिक्रिया संदर्भ हमेशा CXF में स्थानीय थ्रेड है)

  • सेटिंग नाली पर - अगर आप कोड या विन्यास का उपयोग सीधे नाली हेरफेर करने के लिए (TLS सेटिंग या इसी तरह के सेट करना चाहते), उन थ्रेड नहीं कर रहे हैं सुरक्षित। कंड्यूट प्रति-उदाहरण है और इस प्रकार उन सेटिंग्स साझा की जाएंगी। इसके अलावा, अगर आप FailoverFeature और लोडबैलेंस फीचर का उपयोग करते हैं, तो कंड्यूट को फ्लाई पर बदल दिया जाता है। इस प्रकार, कंडिट पर सेट सेटिंग्स सेटिंग थ्रेड पर उपयोग करने से पहले खो सकती है।

  • सत्र समर्थन - यदि आप सत्र समर्थन चालू करते हैं ( jaxws spec देखें), सत्र कुकी को कंड्यूट में संग्रहीत किया जाता है। इस प्रकार, यह कंड्यूट सेटिंग्स पर उपर्युक्त नियमों में गिर जाएगा और इस प्रकार धागे में साझा किया जाएगा।
  • WS-सुरक्षा टोकन - उपयोग WS-SecureConversation या WS-ट्रस्ट, पुनर्प्राप्त टोकन Endpoint/प्रॉक्सी में कैश है, तो अतिरिक्त (और महंगे) टोकन प्राप्त करने के लिए एसटीएस करने के लिए कॉल से बचने के लिए। इस प्रकार, एकाधिक धागे टोकन साझा करेंगे। यदि प्रत्येक थ्रेड में अलग-अलग सुरक्षा प्रमाण-पत्र या आवश्यकताएं हैं, तो आपको अलग प्रॉक्सी उदाहरणों का उपयोग करने की आवश्यकता है।

नाली समस्याओं के लिए, आप एक नया ConduitSelector कि एक धागा स्थानीय या इसी तरह का उपयोग करता है स्थापित कर सकता। यद्यपि यह थोड़ा सा जटिल है।

सबसे "सरल" उपयोग के मामलों के लिए, आप एक से अधिक धागे पर CXF प्रोक्सी का उपयोग कर सकते हैं। उपर्युक्त दूसरों के लिए कामकाज की रूपरेखा तैयार करता है।

3

सामान्य में, नहीं।

CXF पूछे जाने वाले प्रश्न http://cxf.apache.org/faq.html#FAQ-AreJAX-WSclientproxiesthreadsafe?

के अनुसार सरकारी JAX-WS जवाब: सं JAX-WS कल्पना के अनुसार, ग्राहक प्रॉक्सी सुरक्षित सूत्र नहीं कर रहे हैं। पोर्टेबल कोड लिखने के लिए, आपको उन्हें गैर धागा सुरक्षित रूप में मानते हैं और उपयोग को सिंक्रनाइज़ या उदाहरणों या इसी तरह का एक पूल का उपयोग करना चाहिए।

सीएक्सएफ उत्तर: सीएक्सएफ प्रॉक्सी कई उपयोग मामलों के लिए थ्रेड सुरक्षित हैं।

अपवादों की एक सूची के लिए अक्सर पूछे जाने वाले प्रश्न देखें।

3

जैसा कि आप उपर्युक्त उत्तरों से देखते हैं कि जेएक्स-डब्ल्यूएस क्लाइंट प्रॉक्सी थ्रेड सुरक्षित नहीं हैं, इसलिए मैं अपने कार्यान्वयन को साझा करना चाहता हूं ताकि अन्य लोग क्लाइंट प्रॉक्सी को कैश कर सकें। मैं वास्तव में एक ही मुद्दा का सामना किया और एक वसंत सेम कि JAX-WS ग्राहक की प्रॉक्सी कैशिंग करता बनाने का फैसला किया। आप अधिक विवरण http://programtalk.com/java/using-spring-and-scheduler-to-store/ देख सकते हैं

import java.util.Map; 
import java.util.concurrent.ConcurrentHashMap; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ScheduledExecutorService; 
import java.util.concurrent.TimeUnit; 

import javax.annotation.PostConstruct; 

import org.apache.commons.lang3.concurrent.BasicThreadFactory; 
import org.apache.logging.log4j.Logger; 
import org.springframework.stereotype.Component; 

/** 
* This keeps the cache of MAX_CUNCURRENT_THREADS number of 
* appConnections and tries to shares them equally amongst the threads. All the 
* connections are created right at the start and if an error occurs then the 
* cache is created again. 
* 
*/ 
/* 
* 
* Are JAX-WS client proxies thread safe? <br/> According to the JAX-WS spec, 
* the client proxies are NOT thread safe. To write portable code, you should 
* treat them as non-thread safe and synchronize access or use a pool of 
* instances or similar. 
* 
*/ 
@Component 
public class AppConnectionCache { 

private static final Logger logger = org.apache.logging.log4j.LogManager.getLogger(AppConnectionCache.class); 

private final Map<Integer, MyService> connectionCache = new ConcurrentHashMap<Integer, MyService>(); 

private int cachedConnectionId = 1; 

private static final int MAX_CUNCURRENT_THREADS = 20; 

private ScheduledExecutorService scheduler; 

private boolean forceRecaching = true; // first time cache 

@PostConstruct 
public void init() { 
    logger.info("starting appConnectionCache"); 
    logger.info("start caching connections"); ;; 
    BasicThreadFactory factory = new BasicThreadFactory.Builder() 
    .namingPattern("appconnectioncache-scheduler-thread-%d").build(); 
    scheduler = Executors.newScheduledThreadPool(1, factory); 

    scheduler.scheduleAtFixedRate(new Runnable() { 
    @Override 
    public void run() { 
    initializeCache(); 
    } 

    }, 0, 10, TimeUnit.MINUTES); 

} 

public void destroy() { 
    scheduler.shutdownNow(); 
} 

private void initializeCache() { 
    if (!forceRecaching) { 
    return; 
    } 
    try { 
    loadCache(); 
    forceRecaching = false; // this flag is used for initializing 
    logger.info("connections creation finished successfully!"); 
    } catch (MyAppException e) { 
    logger.error("error while initializing the cache"); 
    } 
} 

private void loadCache() throws MyAppException { 
    logger.info("create and cache appservice connections"); 
    for (int i = 0; i < MAX_CUNCURRENT_THREADS; i++) { 
    tryConnect(i, true); 
    } 
} 

public MyPort getMyPort() throws MyAppException { 
    if (cachedConnectionId++ == MAX_CUNCURRENT_THREADS) { 
    cachedConnectionId = 1; 
    } 
    return tryConnect(cachedConnectionId, forceRecaching); 
} 

private MyPort tryConnect(int threadNum, boolean forceConnect) throws MyAppException { 
    boolean connect = true; 
    int tryNum = 0; 
    MyPort app = null; 
    while (connect && !Thread.currentThread().isInterrupted()) { 
    try { 
    app = doConnect(threadNum, forceConnect); 
    connect = false; 
    } catch (Exception e) { 
    tryNum = tryReconnect(tryNum, e); 
    } 
    } 
    return app; 
} 

private int tryReconnect(int tryNum, Exception e) throws MyAppException { 
    logger.warn(Thread.currentThread().getName() + " appservice service not available! : " + e); 
    // try 10 times, if 
    if (tryNum++ < 10) { 
    try { 
    logger.warn(Thread.currentThread().getName() + " wait 1 second"); 
    Thread.sleep(1000); 
    } catch (InterruptedException f) { 
    // restore interrupt 
    Thread.currentThread().interrupt(); 
    } 
    } else { 
    logger.warn(" appservice could not connect, number of times tried: " + (tryNum - 1)); 
    this.forceRecaching = true; 
    throw new MyAppException(e); 
    } 
    logger.info(" try reconnect number: " + tryNum); 
    return tryNum; 
} 

private MyPort doConnect(int threadNum, boolean forceConnect) throws InterruptedException { 
    MyService service = connectionCache.get(threadNum); 
    if (service == null || forceConnect) { 
    logger.info("app service connects : " + (threadNum + 1)); 
    service = new MyService(); 
    connectionCache.put(threadNum, service); 
    logger.info("connect done for " + (threadNum + 1)); 
    } 
    return service.getAppPort(); 
} 
} 
0

इस के लिए एक सामान्य समाधान प्रॉक्सी है कि एक मुखौटा के रूप में कार्य का उपयोग करने, एक पूल में एक से अधिक ग्राहक वस्तुओं का उपयोग करने के तो है।

ServiceObjectPool<SomeNonThreadSafeService> servicePool = new ServiceObjectPool<>(createSomeNonThreadSafeService); 
nowSafeService = servicePool .getProxy(SomeNonThreadSafeService.class); 

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^