2012-08-13 17 views
6

मैं उस मामले पर ठोकर खाई जहां @Cacheable का उपयोग करके बनाई गई एओपी प्रॉक्सी स्प्रिंग 3.1.1 में निर्भरता इंजेक्शन को तोड़ देती है। यहां मेरा परिदृश्य है:@ कैशेबल ब्रेक निर्भरता इंजेक्शन

मेरे पास एक इंटरफ़ेस और एक क्लास है जिसे कार्यान्वित विधि पर @ कैशेबल का उपयोग करके इस इंटरफेस को कार्यान्वित किया गया है।

उदाहरण इंटरफ़ेस:

public interface ImgService { 
    public byte[] getImage(String name); 
} 

उदाहरण कार्यान्वयन:

public class ImgServiceImpl implements ImgService { 

    @Cacheable(cacheName = "someCache") 
    public byte[] getImage(String name){//TODO}; 

    protected String someOtherMethod(){//}; 
} 

मैं भी JUnit परीक्षण वर्गों के लिए है - एक जो इंटरफेस और एक कार्यान्वयन injects:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" }) 
public class ImgServiceTest { 

    @Inject 
    private ImgService; 
} 

और

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" }) 
public class ImgServiceImplTest { 

    @Inject 
    private ImgServiceImpl; 
} 

इंटरफ़ेस के लिए निर्भरता इंजेक्शन ठीक काम करता है। हालांकि, जब मैं दूसरे टेस्ट कक्षा में कार्यान्वयन इंजेक्शन लगाने के लिए मिलता है मैं एक "autowired निर्भरता इंजेक्शन विफल" मिलता है। मैं इसे डिबग करने के लिए कर रहा था और ऐसा लगता है कि ClassUtils.isAssignableValue() को गलत तरीके से इच्छित प्रकार प्रॉक्सी वर्ग है। यह DefaultListableBeanFactory द्वारा कहा जाता है। क्या भी अजनबी है कि अगर मैं कार्यान्वित विधि से @Cacheable टिप्पणी निकालने और कुछ अन्य संरक्षित/निजी विधि में जोड़ने, निर्भरता इंजेक्शन फिर से ठीक काम करता है है। यह एक बग है और क्या सही दृष्टिकोण इस स्थिति को संभालने के लिए हो सकता है?

+0

यहाँ एक और है अच्छा संदर्भ - http://blog.springsource.org/2012/05/23/understanding-proxy-usage-in-spring/ –

उत्तर

3

ठीक है, इसलिए यहाँ समाधान मैं अंत में आया है।मैं एक सरल विधि है कि org.springframework.aop.framework.Advised वर्ग के इसके कार्यान्वयन के आधार पर प्रॉक्सी से लक्ष्य वस्तु को निकालने के लिए प्रयास करता है कार्यान्वित:

@SuppressWarnings({"unchecked"}) 
public static <T> T getTargetObject(Object proxy, Class<T> targetClass) { 
    if (AopUtils.isJdkDynamicProxy(proxy)) { 
    try { 
     return (T) ((Advised)proxy).getTargetSource().getTarget(); 
    } catch (Exception e) { 
     return null; 
    } 
    } else { 
    return (T) proxy; 
    } 
} 

मेरे कार्यान्वयन परीक्षण वर्ग अब इस तरह दिखता है:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" }) 
public class ImgServiceImplTest { 

    @Inject 
    private ImgService imgService; 

    private ImgServiceImpl imgServiceImpl; 

    @PostConstruct 
    public void setUp() { 
     imgServiceImpl = getTargetObject(imgService, ImgServiceImpl.class); 
    } 


} 
10

यह कोई बग नहीं है, यह एओपी कार्यान्वयन के लिए जेडीके गतिशील प्रॉक्सी का उपयोग करने की अपेक्षाकृत दुष्प्रभाव है।

ImgServiceImpl की संचित करने योग्य विधि प्रकार ImgService के गतिशील प्रॉक्सी के माध्यम से जाना चाहिए करने के लिए सभी कॉल्स के बाद से, वहाँ प्रकार ImgServiceImpl के एक क्षेत्र में यह निर्भरता इंजेक्षन करने के लिए कोई रास्ता नहीं है।

आप @Cacheableprivate करने के लिए या protected विधि, इंजेक्शन से काम करता है क्योंकि @Cacheable इस मामले में प्रभावी नहीं होती जब ले जाने - केवल public तरीकों प्रॉक्सी आधारित AOP का उपयोग कर सलाह दी जा सकती है।

तो, आप या तो खेतों की घोषणा ImgService के रूप में इंजेक्ट किया जा करने के लिए, या लक्ष्य वर्ग आधारित प्रॉक्सी बजाय proxy-target-class = "true" का उपयोग कर उपयोग करने के लिए स्प्रिंग कॉन्फ़िगर करना चाहिए।

फिर भी एक और विकल्प वसंत को AspectJ-based AOP implementation (संकलन-समय या लोड-टाइम बुनाई की आवश्यकता है) का उपयोग करने के लिए कॉन्फ़िगर करना है।

यह वसंत (लेनदेन, सुरक्षा, एसिंक निष्पादन, कैश, कस्टम पहलुओं, आदि) द्वारा प्रदान की गई सभी एओपी-आधारित सुविधाओं पर लागू होता है।

यह भी देखें:

+0

उत्तर के लिए धन्यवाद। यह अभी भी मेरे लिए अजीब लगता है कि ClassUtils विधि इसे संभाल नहीं पाती है, क्योंकि ऐसा लगता है कि अगर यह एक कथन से ज्यादा नहीं है। – kpentchev

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