简体   繁体   中英

Spring AOP for interface and for annotated methods within it

I have service code like this:

@Component
public class MyService implements com.xyz.WithSession {

    public void someMethodWhichDoesNotNeedAutorization() {
        // code S1
    }

    @com.xyz.WithAuthorization
    public void someMethodWhichNeedAutorization() {
        // code S2
    }
}

and aspect like this:

@Aspect
public class MyAspect {

    @Before("target(com.xyz.WithSession)")
    public void adviceBeforeEveryMethodFromClassImplementingWithSession() {
        // code A1
    }

    @Before("target(com.xyz.WithSession) && @annotation(com.xyz.WithAuthorization)")
    public void adviceBeforeWithAuthorizationMethodFromClassImplementingWithSession() {
        // code A2
    }

Annotation looks like:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface WithAuthorization{
}
  • code A1 is called before code S1 -- OK
  • code A1 is called before code S2 -- OK
  • code A2 isn't called before code S2 -- NOT OK

What am I doing wrong?

Code is written in Java 7 with Spring 3.1.3.

Update

I've tried another way. I use 'Around' advice instead of 'Before' and 'After' to have access to ProceedingJoinPoint. In this advice I check with reflection whether method has annotation 'com.xyz.WithAuthorization' or not:

private boolean isAnnotated(ProceedingJoinPoint proceedingJoinPoint) {
    MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
    return signature.getMethod().isAnnotationPresent(com.xyz.WithAuthorization);
}

My annotation has '@Retention(RetentionPolicy.RUNTIME)' but I see in debugger that annotation is missing on runtime in the method signature. So the problem still exists.

In Spring Reference at this link

eg in Spring reference

@Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)")
public void audit(Auditable auditable) {
    AuditCode code = auditable.value();
    // ...
}

the execution of any method defined by the AccountService interface:

execution(* com.xyz.service.AccountService.*(..))

any join point (method execution only in Spring AOP) where the executing method has an @Transactional annotation:

@annotation(org.springframework.transaction.annotation.Transactional)

I suggest you to use...

@Before("execution(* com.xyz.WithSession.*(..)) && @annotation(authorization)")
public void adviceBeforeWithAuthorizationMethodFromClassImplementingWithSession(WithAuthorization authorization) {
    // code A2
}

Your second pointcut

@Before("target(com.xyz.WithSession) && @annotation(com.xyz.WithAuthorization)")

fails in two ways. First the

target(com.xyz.WithSession)

matches only classes, not methods. So like @Xstian pointed out you should use something along the lines of

execution(* com.whatever.MyService.*(..))

to match all methods inside the MyService class.

Second problem is the

@annotation(com.xyz.WithAuthorization)

where the argument should be name that matches the argument name in the advice. So you use @annotation(someArgumentName) and then have com.xyz.WithAuthorization someArgumentName as your advice methods argument.

Probably your annotation does not have runtime retention:

@Retention(RetentionPolicy.RUNTIME)
public @interface WithAuthorization {}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM