2010-10-15 14 views
6

क्या फैक्ट्री या प्रॉक्सी बनाना संभव है जो तय कर सकता है कि थ्रेड चल रहा है (वेब) अनुरोध या पृष्ठभूमि-प्रक्रिया (यानी शेड्यूलर) और उसके बाद उस जानकारी के आधार पर, यह एक सत्र बीन या प्रोटोटाइप बीन बनाता है?वसंत: संदर्भ (सत्र/वेब या स्थानीय धागा/पृष्ठभूमि प्रक्रिया) पर निर्भर बीन इंजेक्ट करें

उदाहरण (छद्म स्प्रिंग config :)

<bean id="userInfoSession" scope="session" /> 
<bean id="userInfoStatic" scope="prototype" /> 

<bean id="currentUserInfoFactory" /> 

<bean id="someService" class="..."> 
    <property name="userInfo" ref="currentUserInfoFactory.getCurrentUserInfo()" /> 
</bean> 

मुझे आशा है कि यह मेरे सवाल को समझने के लिए आसान बना देता है ...


मेरे समाधान

यह देर से करने के लिए करने के लिए कभी नहीं अपने प्रश्न अपडेट करें;)। मैंने इसे क्लाइंट सत्र के दो अलग-अलग उदाहरणों, एक सत्र स्कोप्ड क्लाइंट सत्र और एक सिंगलटन स्कोप्ड सत्र के साथ हल किया। दोनों सामान्य सेम हैं।

<bean id="sessionScopedClientSession" class="com.company.product.session.SessionScopedClientSession" scope="session"> 
    <aop:scoped-proxy /> 
</bean> 

<bean id="singletonScopedClientSession" class="com.company.product.session.SingletonScopedClientSession" /> 

<bean id="clientSession" class="com.company.product.session.ClientSession"> 
    <property name="sessionScopedClientSessionBeanName" value="sessionScopedClientSession" /> 
    <property name="singletonScopedClientSessionBeanName" value="singletonScopedClientSession" /> 
</bean> 

ClientSession फिर अगर सिंगलटन या सत्र दायरे तय करेगा:

private IClientSession getSessionAwareClientData() { 
    String beanName = (isInSessionContext() ? sessionScopedClientSessionBeanName : singletonScopedClientSessionBeanName); 
    return (IClientSession) ApplicationContextProvider.getApplicationContext().getBean(beanName); 
} 

कहाँ सत्र प्रकार इस के माध्यम से इकट्ठा किया जा सकता है:

private boolean isInSessionContext() { 
    return RequestContextHolder.getRequestAttributes() != null; 
} 

सभी वर्गों एक इंटरफेस IClientSession कहा जाता है को लागू। सिंगलटनस्कोप्ड और सत्र स्कोप्ड बीन्स दोनों बेस क्लाइंट सत्र से फैले हुए हैं जहां कार्यान्वयन पाया जाता है। अब

@Resource 
private ClientSession clientSession; 

    ... 

public void doSomething() { 
    Long orgId = clientSession.getSomethingFromSession(); 
} 

अगर हम एक कदम आगे हम सत्र के लिए एक एम्यूलेटर की तरह कुछ लिख सकते हैं जाना:

हर सेवा तो ग्राहक सत्र यानी उपयोग कर सकते हैं। यह सिंगलटन सत्र क्लाइंट सत्र (जो किसी अनुरोध के संदर्भ में नहीं है) को प्रारंभ करके किया जा सकता है। अब सभी सेवाओं को एक ही clientSession उपयोग कर सकते हैं और हम अभी भी "अनुकरण" कर सकते हैं एक उपयोगकर्ता यानी:

 clientSessionEmulator.startEmulateUser(testUser); 
     try { 
      service.doSomething(); 
     } finally { 
      clientSessionEmulator.stopEmulation(); 
     } 

एक और सलाह: SingletonScoped clientSession उदाहरण में सूत्रण के बारे में ध्यान रखना! वाह, मैंने सोचा कि मैं इसे कम लाइनों के साथ कर सकता हूं;) यदि आप इस दृष्टिकोण के बारे में अधिक जानना चाहते हैं तो मुझसे संपर्क करने में संकोच न करें।

उत्तर

1

आपका rephrase वास्तव में काफी सरल :)

आपका RequestContextHolder.getRequestAttributes() के उपयोग currentUserInfoFactory बना सकता है। यदि कोई सत्र मौजूद है और कॉलिंग थ्रेड से जुड़ा हुआ है, तो यह एक गैर-शून्य ऑब्जेक्ट लौटाएगा, और फिर आप संदर्भ से सत्र-स्कोप्ड बीन को सुरक्षित रूप से पुनर्प्राप्त कर सकते हैं। यदि यह शून्य हो जाता है, तो आपको इसके बजाय प्रोटोटाइप-स्कोप्ड बीन लाया जाना चाहिए।

यह बहुत साफ नहीं है, लेकिन यह आसान है, और काम करना चाहिए।

public final class SessionScopeContextLoader extends GenericXmlContextLoader { 

    protected void customizeContext(final GenericApplicationContext context) { 
    final SessionScope testSessionScope = new SessionScope(); 
    context.getBeanFactory().registerScope("superscope", testSessionScope); 
    } 
    ... 
} 

तो फिर तुम सिंगलटन के लिए एक इसी एक बनाने के (सिर्फ स्टैटिक्स के साथ अपने स्वयं गुंजाइश बनाने)

तो फिर तुम बस:

+0

मैं इसे आज़माउंगा। कभी-कभी सबसे सरल समाधान सबसे अच्छा होता है और यदि यह काम करता है, तो यह साफ क्यों नहीं है? कुछ अन्य समाधान? –

+1

@ फ्रैंक: कोड जो 'RequestContextHolder' का उपयोग करता है, आमतौर पर परीक्षण करना मुश्किल होता है। इसी कारण से, इसे निराश किया जाना चाहिए। – skaffman

1

दो कस्टम संदर्भ लोडर कि विभिन्न कार्यान्वयन के लिए एक ही दायरे defintion बाँध बनाएं दो संदर्भों में से प्रत्येक के लिए xml स्टार्टअप में उपयुक्त संदर्भ लोडर निर्दिष्ट करें।

+0

मुझे वेबकॉन्टेक्स्ट में उपयुक्त संदर्भ लोडर कहां निर्दिष्ट करना चाहिए? मुझे वास्तव में कस्टम दायरे के बारे में बात नहीं है, क्षमा करें। मुझे आपका रूपांतरण यहां मिला है http://stackoverflow.com/questions/450557/custom-spring-scopes लेकिन यह मुझे बिंदु नहीं मिला ... –

2

मैंने बीन्स इंजेक्ट करने के लिए छोटे सार्वभौमिक कामकाज को संदर्भ पर निर्भर करता है।

अनुमान हम दो सेम है:

<bean class="xyz.UserInfo" id="userInfo" scope="session" /> 
<bean class="xyz.UserInfo" id="userInfoSessionLess" /> 

हम उपयोग करने के लिए वेब उपयोगकर्ता कार्यों और उदाहरण के लिए पृष्ठभूमि सेवाओं के लिए "userInfoSessionLess" सेम के लिए "userInfo" सेम चाहते हैं।

public class MYSessionScope extends SessionScope implements ApplicationContextAware { 
    private static final String SESSION_LESS_POSTFIX = "SessionLess"; 
    private ApplicationContext applicationContext; 
    public Object get(String name, ObjectFactory objectFactory) { 
    if (isInSessionContext()) { 
     log.debug("Return session Bean... name = " + name); 
     return super.get(name, objectFactory); 
    } else { 
     log.debug("Trying to access session Bean outside of Request Context... name = " + name + " return bean with name = " + name + SESSION_LESS_POSTFIX); 
     return applicationContext.getBean(name.replace("scopedTarget.", "") + SESSION_LESS_POSTFIX); 
    } 
    } 
    private boolean isInSessionContext() { 
    return RequestContextHolder.getRequestAttributes() != null; 
    } 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
    this.applicationContext = applicationContext; 
    } 
} 

रजिस्टर नई गुंजाइश:

@Autowired 
//You will get "java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request?" for session less services. 
//We can fix it and autowire "userInfo" or "userInfoSessionLess" depends on context... 
private UserInfo userInfo; 

public save(Document superSecureDocument) { 
    ... 
    superSecureDocument.lastModifier = userInfo.getUser(); 
    ... 
} 

अब हम यह काम करने के लिए कस्टम सत्र दायरे बनाने की जरूरत है: वा भी उदाहरण के लिए, कोड लिखने के लिए और संदर्भ के बारे में सोचना नहीं चाहते हैं:

<bean class="xyz.UserInfo" id="userInfo" scope="mySession" autowire-candidate="true"/> 
<bean class="xyz.UserInfo" id="userInfoSessionLess" autowire-candidate="false"/> 
:

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> 
    <property name="scopes"> 
     <map> 
      <entry key="mySession"> 
       <bean class="com.galantis.gbf.web.MYSessionScope" /> 
      </entry> 
     </map> 
    </property> 
</bean> 

अब हम इस तरह सेम definions संशोधित की जरूरत है

यह सब कुछ है। यदि हम वास्तविक वेब अनुरोध थ्रेड के बाहर बीन का उपयोग करते हैं तो "सत्र सत्र" नाम के साथ बीन का उपयोग सभी "myession" scoped beans के लिए किया जाएगा।

+0

अभी तक आपके समाधान का प्रयास नहीं किया है लेकिन यह मेरे लिए बहुत प्यारा लग रहा है । इसे साझा करने के लिए धन्यवाद! –

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