2010-05-17 7 views
27

मेरे पास जावा 6/स्प्रिंग 3 में लागू एक सर्विस क्लास है जिसे भूमिका से पहुंच प्रतिबंधित करने के लिए एनोटेशन की आवश्यकता होती है।स्प्रिंग एओपी पॉइंटकट जो इंटरफेस पर एनोटेशन से मेल खाता है

मैं एक एनोटेशन कहा जाता RequiredPermission है कि के रूप में अपने मूल्य एक enum बुलाया OperationType से एक या अधिक विशेषता मान को परिभाषित किया है:

public @interface RequiredPermission { 

/** 
* One or more {@link OperationType}s that map to the permissions required 
* to execute this method. 
* 
* @return 
*/ 
OperationType[] value();} 

public enum OperationType { 
     TYPE1, 
     TYPE2; 
} 

package com.mycompany.myservice; 
public interface MyService{ 
    @RequiredPermission(OperationType.TYPE1) 
    void myMethod(MyParameterObject obj); 
} 

package com.mycompany.myserviceimpl; 
public class MyServiceImpl implements MyService{ 
    public myMethod(MyParameterObject obj){ 
     // do stuff here 
    } 
} 

मैं भी निम्नलिखित पहलू परिभाषा है:

/** 
* Security advice around methods that are annotated with 
* {@link RequiredPermission}. 
* 
* @param pjp 
* @param param 
* @param requiredPermission 
* @return 
* @throws Throwable 
*/ 
@Around(value = "execution(public *" 
     + " com.mycompany.myserviceimpl.*(..))" 
     + " && args(param)" + // parameter object 
     " && @annotation(requiredPermission)" // permission annotation 

, argNames = "param,requiredPermission") 
public Object processRequest(final ProceedingJoinPoint pjp, 
     final MyParameterObject param, 
     final RequiredPermission requiredPermission) throws Throwable { 
    if(userService.userHasRoles(param.getUsername(),requiredPermission.values()){ 
     return pjp.proceed(); 
    }else{ 
     throw new SorryButYouAreNotAllowedToDoThatException(
      param.getUsername(),requiredPermission.value()); 
    } 
} 

पैरामीटर ऑब्जेक्ट में उपयोगकर्ता नाम होता है और मैं विधि तक पहुंच की अनुमति देने से पहले उपयोगकर्ता के लिए आवश्यक भूमिका देखना चाहता हूं।

जब मैं MyServiceImpl में विधि पर एनोटेशन डालता हूं, तो सबकुछ ठीक काम करता है, पॉइंटकट मेल खाता है और पहलू काटता है। हालांकि, मेरा मानना ​​है कि एनोटेशन सेवा अनुबंध का हिस्सा है और इंटरफ़ेस के साथ प्रकाशित होना चाहिए एक अलग एपीआई पैकेज। और जाहिर है, मैं दोनों सेवा परिभाषा और कार्यान्वयन (डीआरवाई) पर एनोटेशन डालना नहीं चाहूंगा।

मुझे पता है कि वसंत एओपी में ऐसे मामले हैं जहां एनोटेशन द्वारा पहलुओं को एक इंटरफ़ेस विधियों (जैसे लेनदेन) ट्रिगर किया जाता है। क्या यहां कोई विशेष वाक्यविन्यास है या यह बॉक्स के बाहर सिर्फ असंभव है।

पीएस: मैंने अपनी वसंत कॉन्फ़िगरेशन पोस्ट नहीं की है, क्योंकि ऐसा लगता है कि यह ठीक काम कर रहा है। और नहीं, वे न तो मेरी मूल कक्षा और न ही विधि नाम हैं।

पी पी एस:

<aop:aspectj-autoproxy proxy-target-class="false" /> 

<bean class="com.mycompany.aspect.MyAspect"> 
    <property name="userService" ref="userService" /> 
</bean> 
+0

तो, अगर मैं सही ढंग से समझ, सबसे अच्छा समाधान है कि आप अपने मूल प्रश्न के लिए मिला (यानी, में एनोटेशन होने इंटरफेस, कार्यान्वयन में नहीं) इंटरफेस में विधि की टिप्पणियों को जानने के लिए सेवा प्रदाता इंटरफेस के पूरे पैकेज से मिलान करना है, और फिर ProceedingJoinPoint पर आत्मनिरीक्षण करना है? क्या यह भी संभव है? यह एक महान धागा है, और एक ही प्रश्न के साथ एक नया शुरू नहीं करना चाहता! धन्यवाद!! – espinchi

+0

@espinchi वास्तव में मैं इतना निराश था कि मैंने इंटरफ़ेस से कार्यान्वयन कक्षा में सभी टिप्पणियों की प्रतिलिपि बनाई और लागू किया कि एक कठोर यूनिट परीक्षण के साथ जो दोनों इंटरफेस पर सभी विधियों की जांच करता है और समान एनोटेशन के लिए कक्षा को कार्यान्वित करता है। बिल्कुल नहीं, एओपी, मुझे पता है। मैं कहूंगा कि यह विश्वसनीय रूप से काम नहीं करता है, सभी –

उत्तर

28

तो मैं समझता हूँ कि आप को सही, आप एक pointcut कि कक्षाओं कि MyService प्रदान करता है और व्याख्या की और साथ में सभी तरीकों पाता हैं: वास्तव में, यहाँ मेरी वसंत config के प्रासंगिक हिस्सा है पसंदीदा तर्क।

मेरा प्रस्ताव है कि आप बदल देते हैं:

execution(public * com.mycompany.myserviceimpl.*(..)) 

साथ:

execution(public * com.mycompany.myservice.MyService+.*(..)) 

धन चिह्न आप एक joinpoint MyService वर्ग या एक वर्ग है कि यह फैली मिलान करना चाहते हैं प्रयोग किया जाता है।

मुझे आशा है कि इससे मदद मिलती है!

+0

के बाद एक छोटा टाइपो है। यह वास्तव में है: निष्पादन (सार्वजनिक * com.mycompany.myservice.MyService +। * (..)) लेकिन यह एक आकर्षण की तरह काम करता है। बहुत बहुत धन्यवाद!!! –

+0

यह अच्छा है! मैं अपने जवाब को सभी विधियों पर वाइल्डकार्ड भी शामिल करने के लिए सही कर दूंगा। – Espen

+1

मुझे बहुत बाद में एहसास हुआ कि यह पूरी तरह से सही नहीं है (हालांकि यह शायद सबसे अच्छा शर्त है)। मैं एनोटेशन सेवा इंटरफ़ेस विधि पर होना चाहता था, लेकिन यह केवल तभी काम करता है जब एनोटेशन कार्यान्वयन विधि पर हो। और चूंकि मुझे इस व्यवहार की भी आवश्यकता है: http://stackoverflow.com/questions/3100228/spring-aop-pointcut-expression-to-access-method-return-type, मुझे पॉइंटकट को न्यूनतम रखना होगा और कार्यवाही बिंदु वस्तु को जांचना होगा खुद। –

4

एस्पेन, अपने कोड केवल एक ही वर्ग के लिए काम करता है:। मैं * com.mycompany.services में सभी सेवाओं के लिए इस व्यवहार चाहते

execution(public * com.mycompany.myservice.MyService+.*(..)) 

लेकिन क्या हुआ अगर ** पैकेज?

+1

यह ठीक काम करता है: निष्पादन (सार्वजनिक * com.mycompany.myservice। * +। * (..)) –

0

मैंने एक ही समस्या में भाग लिया है, हालांकि ऊपर दिए गए सुझाव मदद नहीं करते हैं। मैं केवल एक pointcut के रूप में इस है:

execution(public * com.mycompany.myservice.MyService+.*(..)) 

फिर सलाह शुरू हो जाती है। हालांकि, अगर मैं इसे जोड़ता हूं:

&& @annotation(x.y.z.Logged) 

तब सलाह नहीं दी जाती है। MyService इंटरफ़ेस में अपनी विधियों में से एक पर और इसके प्रकार की घोषणा पर भी एक @ लॉग एनोटेशन शामिल है।

+1

&& @annotation (myparam) का उपयोग करने का प्रयास करें और आपको पहलू को मेरे प्रकार के myparam नामक पैरामीटर दें (भले ही आप इसकी आवश्यकता नहीं है) –

+1

यह या तो काम नहीं करता है। यहाँ मेरी सलाह है: "।। निष्पादन (सार्वजनिक * abcdservices * + * (..)) &&" @Around (मूल्य = \t \t \t + "लक्ष्य (सेम) &&" \t \t \t + "@annotation (लॉग) ", argNames =" बीन, लॉग ") – user348237

+1

yup, यह सही है। एनोटेशन कार्यान्वयन विधि पर होना चाहिए, सेवा इंटरफ़ेस विधि नहीं। –

0

आपको अपने @RequiredPermission एनोटेशन में @Inherited एनोटेशन जोड़ना चाहिए।

http://download.oracle.com/javase/6/docs/api/java/lang/annotation/Inherited.html

+6

'@ विरासत 'कक्षा स्तर पर काम करता है, विधि स्तर नहीं:" ध्यान दें कि इस मेटा-एनोटेशन प्रकार का कोई प्रभाव नहीं पड़ता है यदि एनोटेटेड प्रकार का उपयोग कक्षा के अलावा किसी अन्य चीज़ को एनोटेट करने के लिए किया जाता है। ध्यान दें कि यह मेटा-एनोटेशन केवल एनोटेशन को सुपरक्लास से विरासत में प्राप्त करने का कारण बनता है; कार्यान्वित इंटरफेस पर एनोटेशन का कोई प्रभाव नहीं पड़ता है। " –

+0

उसे नहीं पता था ... धन्यवाद! –

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