2010-05-17 4 views
27

역할에 의한 액세스를 제한하기 위해 주석이 필요한 Java 6/Spring 3에서 구현 된 서비스 클래스가 있습니다.인터페이스에서 주석과 일치하는 Spring AOP pointcut

I는 그 값이 열거라고 OPERATIONTYPE에서 하나 개 이상의 특성 값으로 가지는 주석이라고 RequiredPermission 정의한 :

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 
    } 
} 

I 또한 다음의 화면 정의 가지고

/** 
* 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의 메소드에 어노테이션을 추가하면 모든 것이 잘 작동하고 포인트 컷이 일치하며 애스펙트가 시작됩니다. 그러나 어노테이션이 서비스 계약의 일부이며 인터페이스가 게시되어야한다고 생각합니다. 별도의 API 패키지 그리고 분명히, 주석을 서비스 정의와 구현 (DRY)에 두는 것을 좋아하지 않을 것입니다.

애스펙트가 하나의 인터페이스 메소드 (예 : 트랜잭션)에 의해 트리거되는 Spring AOP의 경우가 있음을 알고 있습니다. 여기에 특별한 문법이 있나? 아니면 상자 밖에서는 불가능한 일이다.

추신 : 봄철 설정을 게시하지 않았습니다. 정상적으로 작동하는 것 같습니다. 그리고 아니요, 그것들은 원래의 클래스도 메소드 이름도 아닙니다.

PPS : 나는 당신이 올바른 이해한다면

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

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

그래서, 내가 제대로 이해한다면, 당신은 원래의 질문에 대해 볼 수있는 가장 좋은 방법 (즉,에 주석을 가진 인터페이스는 구현에 포함되지 않음)는 서비스 공급자 인터페이스의 전체 패키지를 일치시킨 다음 ProceedingJoinPoint에서 인터페이스의 메서드 주석을 찾기 위해 인트로 스펙 트하는 것입니다. 그게 가능한가? 이것은 대단한 스레드이며 동일한 질문으로 새로운 것을 시작하고 싶지 않습니다! 감사!! – espinchi

+0

@espinchi 실제로 저는 인터페이스에서 구현 된 클래스로 모든 주석을 복사하고 인터페이스의 모든 메소드를 검사하고 동일한 주석을 구현하는 클래스를 구현하는 rigurus unit 테스트를 실시하여 매우 실망했습니다. 정확히 AOP가 아니야, 나도 알아. 나는 그것이 안정적으로 작동하지 않는다고 말하고 싶지만, 결국은 –

답변

28

, 당신은이면 MyService를 확장하고 주석과 함께 클래스에있는 모든 방법을 찾아 포인트 컷을 원하는 : 사실, 여기 내 스프링 설정의 관련 부분입니다 선호하는 주장들.

는 당신이 교체 할 것을 제안 :

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

로 :

당신은 joinpoint를가이면 MyService 클래스하거나 확장하는 클래스를 일치시킬 경우 더하기 기호를 사용
execution(public * com.mycompany.myservice.MyService+.*(..)) 

.

도움이 되었기를 바랍니다.

+0

작은 오타가 있습니다. 실제로 : 실행 (공개 * com.mycompany.myservice.MyService +. * (..)) 하지만 그것은 매력처럼 작동합니다. 고마워요 !!! –

+0

좋습니다! 모든 방법에도 와일드 카드를 포함하도록 답변을 수정합니다. – Espen

+1

나는 이것이 완전히 정확하지 않다는 것을 나중에 깨달았습니다. (아마 이것이 최선의 방법 일지 모르지만). 어노테이션이 서비스 인터페이스 메소드에 있기를 원했지만 어노테이션이 구현 메소드에있는 경우에만 작동합니다. 그리고 이후에도이 동작이 필요하기 때문에 : http://stackoverflow.com/questions/3100228/spring-aop-pointcut-expression-to-access-method-return-type, pointcut을 최소화하고 proceedingjoinpoint 객체를 확인해야합니다. 자기. –

4

에스 펜, 코드는 하나 개의 클래스에 대해 작동합니다. 내가 * com.mycompany.services의 모든 서비스에 대해이 동작을 원하지

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

하지만 경우 ** 패키지?

+1

잘 작동합니다. 실행 (public * com.mycompany.myservice. * +. * (..)) –

0

동일한 문제가 발생했지만 위의 제안 사항이 도움이되지 않습니다. 난 단지 포인트 컷으로이있는 경우 :

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

는 그런 충고가 호출됩니다. 그러나이를 다음과 같이 추가하면 :

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

그러면 조언이 호출되지 않습니다. MyService 인터페이스에는, 메소드의 1 개 (살), 및 형태 선언에서도 @Logged 주석이 포함되어 있습니다.

+1

&& @annotation (myparam)을 사용하고 Logged 유형의 myparam이라는 매개 변수가 있다고 생각해 봅니다. 필요 없음) –

+1

이것은 작동하지 않습니다. 여기 내 조언이다 ".. 실행 (공공 * abcdservices * + * (..)) &&" @Around (값 =이 \t \t \t + "대상 (콩) &&" \t \t \t + "@annotation (로그) ", argNames ="bean, logged ") – user348237

+1

그래, 맞아. 어노테이션은 서비스 인터페이스 메소드가 아닌 구현 메소드에 있어야한다. –

0

@Inherited 주석을 @RequiredPermission 주석에 추가해야합니다.

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

+6

'@ Inherited'only는 메소드 레벨이 아닌 클래스 레벨에서만 작동합니다 : "주석이 달린 타입이 클래스가 아닌 다른 것을 주석하기 위해 사용된다면이 메타 주석 타입은 효과가 없습니다. 또한이 메타 주석 어노테이션이 슈퍼 클래스에서 상속되도록하고, 구현 된 인터페이스의 어노테이션은 아무 효과가 없습니다. " –

+0

몰랐습니다 ... 고마워요! –