2008-09-24 15 views
186

क्या स्प्रिंग एप्लिकेशन में एप्लिकेशनकॉन्टेक्स्ट की एक प्रति स्थिर/वैश्विक रूप से अनुरोध करने का कोई तरीका है?स्प्रिंग एप्लिकेशन संदर्भ प्राप्त करना

मुख्य वर्ग मानते हैं कि एप्लिकेशन संदर्भ शुरू होता है और इसे शुरू करने के लिए किसी भी कक्षा में कॉल स्टैक के माध्यम से इसे पारित करने की आवश्यकता होती है, या क्या क्लास के पहले बनाए गए संदर्भ के लिए पूछने का कोई तरीका है?

उत्तर

158

यदि ऑब्जेक्ट को कंटेनर तक पहुंच की आवश्यकता है तो कंटेनर में एक बीन है, बस BeanFactoryAware या ApplicationContextAware इंटरफेस को लागू करें।

यदि कंटेनर के बाहर किसी ऑब्जेक्ट को कंटेनर तक पहुंच की आवश्यकता है, तो मैंने वसंत कंटेनर के लिए standard GoF singleton pattern का उपयोग किया है। इस तरह, आपके पास केवल आपके आवेदन में एक सिंगलटन है, शेष कंटेनर में सभी सिंगलटन बीन्स हैं।

+12

एप्लिकेशनकॉन्टेक्स - एप्लिकेशनकॉन्टेक्स्टवेयर के लिए एक बेहतर इंटरफ़ेस भी है। BeanFactoryAware काम करना चाहिए, लेकिन यदि आपको ऐप संदर्भ कार्यक्षमता की आवश्यकता है तो आपको इसे एप्लिकेशन संदर्भ में डालना होगा। – MetroidFan2002

+2

टिप के लिए धन्यवाद, मैंने जवाब अपडेट किया है। –

+0

@ डॉन किर्कबी सिंगलटन पैटर्न का उपयोग करने से आपके कंटेनर क्लास को आपके कंटेनर क्लास के भीतर एक स्थैतिक विधि से instanciating का मतलब है ... एक बार जब आप किसी ऑब्जेक्ट को "मैन्युअल रूप से" उत्पन्न करते हैं तो यह अब स्प्रिंग द्वारा प्रबंधित नहीं होता है: आप इस समस्या से कैसे निपटते हैं? – Antonin

35

यहाँ एक अच्छा तरीका है (? कौन सा मुझे लगता है एक सिंगलटन हो गया है) (मेरा नहीं, मूल संदर्भ यहाँ है: http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html

मैं इस दृष्टिकोण का उपयोग किया है और यह ठीक काम करता है मूल रूप से यह एक आसान है। सेम कि। वसंत config यह प्रारंभ है में यह संदर्भित करके आवेदन संदर्भ के लिए एक (स्थिर) संदर्भ रखती है।

मूल रेफरी पर एक नजर डालें, यह बहुत स्पष्ट है।

+2

बहुत अच्छा ब्लॉग वहाँ प्रवेश! – Chris

+4

यदि आप यूनिट टेस्ट के दौरान चलने वाले कोड से 'गेटबीन' कहते हैं तो वह दृष्टिकोण विफल हो सकता है क्योंकि वसंत संदर्भ आपके द्वारा पूछे जाने से पहले स्थापित नहीं किया जाएगा। इसकी एक दौड़ की स्थिति मैं इस दृष्टिकोण का सफलतापूर्वक उपयोग करने के 2 साल बाद आज ही झुका। – HDave

+0

मैं एक ही चीज़ में चल रहा हूं .. यूनिट परीक्षण से नहीं बल्कि डेटाबेस ट्रिगर से .. कोई सुझाव? –

4

ContextSingletonBeanFactoryLocator पर एक नजर डालें। यह स्प्रिंग के संदर्भों को पकड़ने के लिए स्थिर पहुंच प्रदान करता है, मानते हैं कि वे एच कुछ तरीकों से पंजीकृत किया गया है।

यह सुंदर नहीं है, और शायद आप जितना अधिक जटिल चाहते हैं, लेकिन यह काम करता है।

11

इससे पहले कि आप अन्य कोई भी सुझाव लागू, अपने आप को इन सवालों को पूछने ...

  • मैं क्यों ApplicationContext प्राप्त करने की कोशिश कर रहा हूँ?
  • क्या मैं प्रभावी रूप से ServiceContext को सेवा लोकेटर के रूप में उपयोग कर रहा हूं?
  • क्या मैं एप्लिकेशन कॉन्टेक्स्ट को एक्सेस करने से बच सकता हूं?

इन सवालों के जवाब कुछ प्रकार के अनुप्रयोगों (उदाहरण के लिए, वेब ऐप्स) उदाहरण के लिए आसान हैं, लेकिन वे किसी भी तरह से पूछने योग्य हैं।

एप्लिकेशन कॉन्टेक्स्ट तक पहुंचने से पूरे निर्भरता इंजेक्शन सिद्धांत का उल्लंघन होता है, लेकिन कभी-कभी आपको अधिक पसंद नहीं मिलता है।

+5

एक अच्छा उदाहरण जेएसपी टैग है; उनकी रचना सर्वलेट कंटेनर द्वारा घिरा हुआ है, इसलिए उनके पास संदर्भ को स्थिर रूप से प्राप्त करने के अलावा कोई विकल्प नहीं है। वसंत आधार टैग कक्षाएं प्रदान करता है, और वे संदर्भों को प्राप्त करने के लिए बीनफैक्टरीलोकेटर का उपयोग करते हैं। – skaffman

18

मेरा मानना ​​है कि आप SingletonBeanFactoryLocator का उपयोग कर सकते हैं। beanRefFactory.xml फ़ाइल वास्तविक applicationContext पकड़ होता है, वह कुछ इस तरह जाना होगा:

BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance(); 
BeanFactoryReference bf = bfl.useBeanFactory("mainContext"); 
SomeService someService = (SomeService) bf.getFactory().getBean("someService"); 

:

<bean id="mainContext" class="org.springframework.context.support.ClassPathXmlApplicationContext"> 
    <constructor-arg> 
     <list> 
      <value>../applicationContext.xml</value> 
     </list> 
    </constructor-arg> 
</bean> 

और कोड से जहाँ कुछ इस तरह होगा applicationcontext से एक सेम प्राप्त करने के लिए स्प्रिंग टीम इस वर्ग और यादय के उपयोग को हतोत्साहित करती है, लेकिन यह मुझे अच्छी तरह अनुकूल बनाती है जहां मैंने इसका इस्तेमाल किया है।

6

यदि आप वेब-ऐप का उपयोग करते हैं तो सर्वलेटफिल्टर और थ्रेडलोकल का उपयोग करके सिंगलेट का उपयोग किए बिना एप्लिकेशन संदर्भ तक पहुंचने का एक और तरीका भी है।फ़िल्टर में आप WebApplicationContextUtils का उपयोग करके एप्लिकेशन संदर्भ तक पहुंच सकते हैं और थैडलोकल में एप्लिकेशन संदर्भ या आवश्यक बीन्स स्टोर कर सकते हैं।

सावधानी: यदि आप थ्रेडलोकल को अनसेट करना भूल जाते हैं तो आवेदन को अनावश्यक करने की कोशिश करते समय आपको बुरा समस्याएं मिलेंगी! इस प्रकार, आपको इसे सेट करना चाहिए और तुरंत कोशिश करना शुरू करें जो अंत में भाग में थ्रेडलोकल को अनसेट करता है।

बेशक, यह अभी भी एक सिंगलटन का उपयोग करता है: थ्रेडलोकल। लेकिन वास्तविक सेम अब और होने की जरूरत नहीं है। यहां तक ​​कि अनुरोध-स्कोप्ड भी हो सकता है, और यह समाधान भी काम करता है यदि आपके पास ईएआर में मुक्ति के साथ किसी एप्लिकेशन में एकाधिक WARs हैं। फिर भी, आप सादे सिंगलेट्स के उपयोग के रूप में थ्रेडलोकल के इस उपयोग को खराब मान सकते हैं। ;-)

शायद वसंत पहले से ही एक समान समाधान प्रदान करता है? मुझे एक नहीं मिला, लेकिन मुझे यकीन नहीं है।

108

आप ApplicationContextAware लागू कर सकते हैं या सिर्फ @Autowired का उपयोग करें:

public class SpringBean { 
    @Autowired 
    private ApplicationContext appContext; 
} 

SpringBeanApplicationContext इंजेक्शन, जो भीतर इस सेम instantiated है होगा। उदाहरण के लिए आप एक बहुत मानक संदर्भों पदानुक्रम के साथ वेब अनुप्रयोग है, तो:

main application context <- (child) MVC context 

और SpringBean मुख्य संदर्भ में घोषित किया जाता है, यह मुख्य संदर्भ इंजेक्शन होगा; अन्यथा, यदि इसे एमवीसी संदर्भ में घोषित किया गया है, तो इसमें एमवीसी संदर्भ इंजेक्शन होगा।

+2

इससे एक गुच्छा में मदद मिली। मुझे स्प्रिंग 2.0 के साथ पुराने ऐप के साथ कुछ अजीब समस्याएं मिली हैं और आपका जवाब एकमात्र तरीका था जिसे मैं एक ही स्प्रिंग आईओसी कंटेनर के साथ एक ही एप्लीकेशन कॉन्टेक्स्ट के साथ काम करने के लिए संवेदना प्राप्त कर सकता था। –

+1

पाठक .. इस वसंतबीन को अपने springconfig.xml में एक बीन के रूप में घोषित करना न भूलें। – supernova

+0

क्या होगा यदि यह पहले से ही बीन है, और मैं Application.getAplicationContext() (सिंगलटन पैटर्न) का उपयोग करता हूं, जो कि नए XXXXAplicationContext (XXXX) का उदाहरण देता है, यह क्यों काम नहीं कर रहा है? मुझे इसे स्वैच्छिक क्यों करना है? – Jaskey

2

ध्यान दें कि वर्तमान ApplicationContext, या एक स्थिर चर में ApplicationContext से ही किसी भी राज्य भंडारण के द्वारा - उदाहरण के लिए सिंगलटन पद्धति का उपयोग कर - आप अपने परीक्षण अस्थिर और अप्रत्याशित कर देगा आप वसंत-परीक्षण का उपयोग कर रहे हैं। ऐसा इसलिए है क्योंकि स्प्रिंग-टेस्ट कैश और उसी संदर्भ में अनुप्रयोग संदर्भों का पुन: उपयोग करता है। उदाहरण के लिए:

  1. टेस्ट एक रन और इसे @ContextConfiguration({"classpath:foo.xml"}) के साथ एनोटेट किया गया है।
  2. टेस्ट बी रन और यह @ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
  3. टेस्ट सी चलाने के साथ टिप्पणी की जाती है और इसके साथ टिप्पणी की जाती है @ContextConfiguration({"classpath:foo.xml"})

जब टेस्ट एक चलाता है, एक ApplicationContext बनाई गई है, और किसी भी सेम ApplicationContextAware implemeting या ApplicationContext autowiring लिख सकते हैं स्थिर चर के लिए।

जब टेस्ट बी टेस्ट एक से एक ही बात होता है चलाता है, और स्थिर चर अब टेस्ट के लिए अंक बी के ApplicationContext

जब टेस्ट सी चलाता है, कोई सेम बनाई गई हैं रूप TestContext (और इस के साथ साथ ApplicationContext) पुन: उपयोग किया जाता है अब आपके पास वर्तमान में बीन्स धारण करने वाले व्यक्ति की तुलना में ApplicationContext पर एक स्थैतिक चर है।

0

कृपया ध्यान दें कि; नीचे दिया गया कोड पहले से लोड किए गए उपयोग का उपयोग करने के बजाय नया एप्लिकेशन संदर्भ बनाएगा।

private static final ApplicationContext context = 
       new ClassPathXmlApplicationContext("beans.xml"); 

भी ध्यान रखें कि beans.xml युद्ध में src/main/resources साधन का हिस्सा यह WEB_INF/classes, जहां के रूप में असली आवेदन applicationContext.xmlWeb.xml में उल्लेख के माध्यम से लोड किया जाएगा का हिस्सा है होना चाहिए।

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>META-INF/spring/applicationContext.xml</param-value> 
</context-param> 

यह ClassPathXmlApplicationContext निर्माता में applicationContext.xml पथ का उल्लेख difficult है। ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml") फ़ाइल का पता लगाने में सक्षम नहीं होगा।

तो एनोटेशन का उपयोग करके मौजूदा एप्लिकेशन कॉन्टेक्स्ट का उपयोग करना बेहतर है।

@Component 
public class OperatorRequestHandlerFactory { 

    public static ApplicationContext context; 

    @Autowired 
    public void setApplicationContext(ApplicationContext applicationContext) { 
     context = applicationContext; 
    } 
} 
1
SpringApplicationContext.java 

import org.springframework.beans.BeansException; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.ApplicationContextAware; 

/** 
* Wrapper to always return a reference to the Spring Application 
Context from 
* within non-Spring enabled beans. Unlike Spring MVC's 
WebApplicationContextUtils 
* we do not need a reference to the Servlet context for this. All we need is 
* for this bean to be initialized during application startup. 
*/ 
public class SpringApplicationContext implements 
ApplicationContextAware { 

    private static ApplicationContext CONTEXT; 

    /** 
    * This method is called from within the ApplicationContext once it is 
    * done starting up, it will stick a reference to itself into this bean. 
    * @param context a reference to the ApplicationContext. 
    */ 
    public void setApplicationContext(ApplicationContext context) throws BeansException { 
    CONTEXT = context; 
    } 

    /** 
    * This is about the same as context.getBean("beanName"), except it has its 
    * own static handle to the Spring context, so calling this method statically 
    * will give access to the beans by name in the Spring application context. 
    * As in the context.getBean("beanName") call, the caller must cast to the 
    * appropriate target class. If the bean does not exist, then a Runtime error 
    * will be thrown. 
    * @param beanName the name of the bean to get. 
    * @return an Object reference to the named bean. 
    */ 
    public static Object getBean(String beanName) { 
    return CONTEXT.getBean(beanName); 
    } 
} 

स्रोत: http://sujitpal.blogspot.de/2007/03/accessing-spring-beans-from-legacy-code.html

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