2012-07-16 15 views
6

हम ThreadLocal का उपयोग करते हुए कुछ डेटाबेस विभाजन जानकारी सेट करने के लिए स्प्रिंग के TransactionInterceptor का उपयोग कर रहे हैं जब भी @Transactional एनोटेशन के साथ चिह्नित एक डीएओ विधि निष्पादित की जाती है। हमें अपने प्रश्नों को अलग-अलग डेटाबेस विभाजनों में रूट करने में सक्षम होने की आवश्यकता है।स्प्रिंग बीन कैसे पता लगा सकता है कि यह स्वयं को एओपी प्रॉक्सी में लपेटा गया है?

यह सबसे डीएओ तरीकों के लिए ठीक काम करता है:

// this causes the invoke method to set a thread-local with the host name of 
// the database server the partition is on 
@Transactional 
public int deleteAll() throws LocalDataException { 

समस्या यह है कि जब हम संदर्भ के लिए डीएओ के अंदर डीएओ प्रॉक्सी वस्तु ही जरूरत है। आमतौर पर हम फोन करने वाले प्रॉक्सी-दाव में पारित करना होगा:

public Pager<Foo, Long> getPager(FooDao proxyDao) { 

इस कोड को जो स्पष्ट रूप से सकल है में ऐसा दिखाई देता है।

fooDao.getPager(fooDao); 

समस्या यह है कि जब हम FooDao के अंदर कर रहे हैं, thisनहीं प्रॉक्सी डीएओ है कि हम की जरूरत है।

क्या बीन के लिए यह बेहतर तकनीक है कि यह इसके आसपास एक प्रॉक्सी रैपर है? मैंने Spring AOPUtils पर देखा है लेकिन मुझे ऑब्जेक्ट के लिए प्रॉक्सी खोजने का कोई तरीका नहीं दिख रहा है। मैं उदाहरण के लिए isAopProxy(...) नहीं चाहता। मैंने Spring AOP docs भी पढ़ा है, लेकिन जब तक मैं अपने स्वयं के एओपी देशी कोड को लागू नहीं करता, तब तक मैं वहां कोई समाधान नहीं देख सकता।

मुझे संदेह है कि मैं ApplicationContextAware उपयोगिता बीन और setProxyDao(...) विधि के साथ डीएओ को इंजेक्ट करने में सक्षम हो सकता हूं, लेकिन यह एक हैक जैसा भी लगता है। कोई अन्य विचार मैं प्रॉक्सी का पता कैसे लगा सकता हूं ताकि मैं इसे बीन के भीतर से उपयोग कर सकूं? किसी भी मदद के लिए धन्यवाद।

+0

मूल Aspectj लोड/संकलन समय का उपयोग कर बुनाई एक विकल्प नहीं है - तो सलाह प्रॉक्सी में बुनाई होगी और आपको प्रॉक्सी का कोई मुद्दा नहीं होना चाहिए और प्रॉक्सी के भीतर यह संदर्भ नहीं होना चाहिए? –

+0

'यह' @ थोरबोजर्न नहीं करेगा क्योंकि पोस्ट स्टेटस के रूप में, मुझे प्रॉक्सी _not_ बीन स्वयं की आवश्यकता है। – Gray

+0

अपना खुद का मूल एओपी लिखना मेरा एकमात्र समाधान @ बिजू हो सकता है। अगर मैं कर सकता हूं तो मैं इससे बचने की उम्मीद कर रहा था। धन्यवाद था। – Gray

उत्तर

4

आप क्या सुझाव दिया है की तर्ज पर एक hacky समाधान, यह देखते हुए कि AspectJ समय या लोड समय बुनाई संकलन आप के लिए काम नहीं करेगा:

public interface ProxyAware<T> { 
    void setProxy(T proxy); 
} 

करते हैं:

इन पंक्तियों के साथ एक अंतरफलक बनाएं अपने दाव के ProxyAware कार्यान्वयन को लागू, अब पिछले चलाने के लिए एक आदेश दिया इंटरफेस के साथ एक BeanPostProcessor बनाने के लिए, इन पंक्तियों के साथ:

public class ProxyInjectingBeanPostProcessor implements BeanPostProcessor, Ordered { 
    @Override 
    public Object postProcessBeforeInitialization(Object bean, String beanName) { 
     return bean; 
    } 

    @Override 
    public Object postProcessAfterInitialization(Object bean, String beanName) { 
     if (AopUtils.isAopProxy((bean))){ 
      try { 
       Object target = ((Advised)bean).getTargetSource().getTarget(); 
       if (target instanceof ProxyAware){ 
        ((ProxyAware) target).setProxy(bean); 
       } 
      } catch (Exception e) { 
       // ignore 
      } 
     } 
     return bean; 
    } 

    @Override 
    public int getOrder() { 
     return Ordered.LOWEST_PRECEDENCE; 
    } 
} 

यह बदसूरत है, लेकिन काम करता है।

+0

ओहोह। स्वादिष्ट। मुझे @ बिजू के रूप में देखना पसंद है। मुझे इसे आज़माएं ... – Gray

+0

मैंने 'ऑर्डर' को हटा दिया क्योंकि ऐसा लगता है कि किसी कारण से मेरे एओपी पर प्रतिकूल प्रभाव पड़ता है। लेकिन अन्यथा यह काम कर रहा है। शायद आपको 'आदेश' हटा देना चाहिए? एक बार फिर धन्यवाद। – Gray

2

स्प्रिंग द्वारा प्रदान की गई एक आसान स्थिर उपयोगिता AopContext.currentProxy() विधि है जो ऑब्जेक्ट को प्रॉक्सी देता है जिस से इसे कॉल किया गया था।

हालांकि इसका उपयोग करना एक बुरा अभ्यास माना जाता है, अर्थात् जावा ईई में भी वही विधि मौजूद है: SessionContext.getBusinessObject()

मैंने इस उपयोगिता विधि और विभिन्न नुकसान के बारे में कुछ लेख लिखे हैं: 1, 2, 3

+0

मैंने यह कहना शुरू कर दिया कि जब मैं कॉल करता हूं तो मैं प्रॉक्सी नहीं था इसलिए कोई मौजूदा प्रॉक्सी नहीं है। लेकिन ऐसा कोई कारण नहीं है कि मैं 'getPager()' विधि को '@ लेनदेन 'के रूप में चिह्नित नहीं कर सकता था, जिस स्थिति में मैं होगा। तो यह सहायक @ टोमाज़ है। धन्यवाद! – Gray

2

बीन में एक बीन संदर्भ इंजेक्ट करने के लिए वसंत का उपयोग करें, यहां तक ​​कि वही बीन, जैसा कि आप किसी भी अन्य बीन संदर्भ के लिए करेंगे। कोई विशेष कार्रवाई की आवश्यकता नहीं है।

इस तरह के एक चर की उपस्थिति क्लास डिज़ाइन में स्पष्ट रूप से स्वीकार करती है कि कक्षा किसी तरह से प्रक्षेपित होने की अपेक्षा करती है।यह जरूरी नहीं है कि एक बुरी चीज है, क्योंकि एओपी व्यवहार को तोड़ने वाले व्यवहार को बदल सकता है।

बीन संदर्भ आमतौर पर एक इंटरफ़ेस के लिए होगा, और यह इंटरफ़ेस आत्म-संदर्भित आंतरिक विधियों के लिए भी एक अलग हो सकता है।

इसे आसान रखें। इस तरह पागलपन निहित है। :-)

अधिक महत्वपूर्ण बात यह सुनिश्चित करें कि अर्थशास्त्र समझ में आता है। ऐसा करने की आवश्यकता एक कोड गंध हो सकती है कि वर्ग अलग-अलग बीन्स में विघटित कई जिम्मेदारियों में मिश्रण कर रहा है।

+0

धन्यवाद केंट। मैं उम्मीद कर रहा था कि मेरे सभी डीएओ में इंजेक्शन न करें। लगता है कि 'बीनपोस्टप्रोसेसर' काम कर रहा है लेकिन मैं इसे ध्यान में रखूंगा। – Gray

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

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