简体   繁体   中英

Aspects implemented as abstract and concrete classes using @AspectJ syntax not working with Spring AOP

I am implementing annotation driver aspects at class level and method level using AspectJ to be used in Spring applications using Spring proxy based AOP.

When AnnotationTimeoutAspect is exposed to Spring Application and using

For Grails applications, set in Config.groovy grails.spring.bean.packages = ['com.xyz.aspect'] or For spring applications <context:component-scan base-package="com.xyz.aspect"/> <aop:aspectj-autoproxy/>

Following error is thrown.

Required parameter names not available when parsing point cut

When the aspect and pointcuts are implemented in single class (no Abstract and Concrete classes) it works as expected.

Abstract and Concrete class separation also works fine when testing locally with JUnit test classes and Load-Time-Weaving. The same doesn't work when using with Spring Proxy based AOP scenario.

My goal is to keep the implementation in Abstract aspect and pointcuts in Concrete aspect so that I can implement multiple Concrete aspects based in my pointcuts needs.

Please let me know if you have any workaround.

Concrete Aspect

@Component
@Order(116)
@Aspect
public class AnnotationTimeoutAspect extends AbstractTimeoutAspect {

    @Pointcut("execution(@com.xyz.annotation.Timeout * *(..)) && @annotation(timeoutConfig)")
    public void executionOfTimeoutMethod(Timeout timeoutConfig) {}

    @Pointcut("execution(public * ((@com.xyz.annotation.Timeout *)+).*(..)) " +
            "&& within(@com.xyz.annotation.Timeout *) && @target(timeoutConfig) " +
            "&& !com.xyz.aspect.SystemArchitecture.groovyMOPMethods()")
    public void executionOfAnyPublicMethodInAtTimeoutType(Timeout timeoutConfig) {}

    @Pointcut("(executionOfTimeoutMethod(timeoutConfig) || executionOfAnyPublicMethodInAtTimeoutType(timeoutConfig))")
    public void timeoutMethodExecution(Timeout timeoutConfig) { }

    @DeclareError("execution(@com.xyz.annotation.Timeout  * *(..) throws !java.util.concurrent.TimeoutException)")
    static final String anError = "Only methods that are declared with throws TimeoutException may have an @Timeout annotation";
}

Abstract Aspect

@Aspect
public abstract class AbstractTimeoutAspect {
    protected final Logger log = LoggerFactory.getLogger(getClass());
    private static class TimeoutThread extends Thread {
        private boolean completed = false;
        private ProceedingJoinPoint point;
        private Throwable throwable;
        private Object value;

        public ProceedingJoinPoint getPoint() {
            return point;
        }

        public Throwable getThrowable() {
            return throwable;
        }

        public Object getValue() {
            return value;
        }

        public boolean isCompleted() {
            return completed;
        }

        public void run() {
            try {
                setValue(point.proceed());
            } catch (Throwable t) {
                setThrowable(t);
            } finally {
                setCompleted(true);
            }
        }

        public void setCompleted(boolean completed) {
            this.completed = completed;
        }

        public void setPoint(ProceedingJoinPoint point) {
            this.point = point;
        }

        public void setThrowable(Throwable throwable) {
            this.throwable = throwable;
        }

        public void setValue(Object value) {
            this.value = value;
        }

    }

    @Around("executionOfAnyPublicMethodInAtTimeoutType(timeoutConfig)")
    public Object timeoutOnClassLevel(final ProceedingJoinPoint point,Timeout timeoutConfig) throws Throwable {
        return  doTimeout(point,timeoutConfig);
    }

    @Around("executionOfTimeoutMethod(timeoutConfig)")
    public Object timeoutOnMethodLevel(final ProceedingJoinPoint point,Timeout timeoutConfig) throws Throwable {
        return  doTimeout(point,timeoutConfig);
    }

    // @Around("timeoutMethodExecution(timeoutConfig)")
    public Object doTimeout(final ProceedingJoinPoint point,Timeout2 timeoutConfig) throws Throwable {
        log.debug(point + " -> " + timeoutConfig);
        Method method = ((MethodSignature) point.getSignature()).getMethod();

        TimeoutThread thread = new TimeoutThread();
        thread.setDaemon(timeoutConfig.daemon());
        thread.setPoint(point);
        thread.start();
        thread.join(timeoutConfig.value());

        if (!thread.isCompleted()) {
            throw new TimeoutException("Method " + method + " exceeded timeout of " + timeoutConfig.value() + " milliseconds");
        } else if (thread.getThrowable() != null) {
            throw thread.getThrowable();
        } else {
            return thread.getValue();
        }
    }

    @Pointcut
    public abstract void executionOfAnyPublicMethodInAtTimeoutType(Timeout timeoutConfig);

    @Pointcut
    public abstract void executionOfTimeoutMethod(Timeout timeoutConfig);

    @Pointcut
    public abstract void timeoutMethodExecution(Timeout timeoutConfig);
}

Error

2014-03-23 16:48:01,924 [localhost-startStop-1] DEBUG annotation.ReflectiveAspectJAdvisorFactory  - Found AspectJ method: public java.lang.Object com.xyz.aspect.AbstractTimeoutAspect.timeoutOnClassLevel(org.aspectj.lang.ProceedingJoinPoint,com.xyz.annotation.Timeout) throws java.lang.Throwable
2014-03-23 16:48:01,925 [localhost-startStop-1] DEBUG annotation.ReflectiveAspectJAdvisorFactory  - Found AspectJ method: public java.lang.Object com.xyz.aspect.AbstractTimeoutAspect.timeoutOnMethodLevel(org.aspectj.lang.ProceedingJoinPoint,com.xyz.annotation.Timeout) throws java.lang.Throwable

Caused by IllegalStateException: Required parameter names not available when parsing pointcut executionOfTimeoutMethod in type com.xyz.aspect.AbstractTimeoutAspect
->>  290 | getDeclaredPointcuts in org.aspectj.weaver.reflect.Java15ReflectionBasedReferenceTypeDelegate
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    800 | getDeclaredPointcuts in org.aspectj.weaver.ReferenceType
|    243 | get . . . in org.aspectj.weaver.ResolvedType$PointcutGetter

You cannot have a @Pointcut in an abstract class. Make another class with all the pointcuts and make it extend this class. The advices can remain here.

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