当前位置: 首页 > 知识库问答 >
问题:

以抽象和具体类的形式实现的方面,使用@AsheJ语法不适用于Spring AOP

许丁雷
2023-03-14

我正在使用AspectJ在类级别和方法级别实现注释驱动程序方面,以用于使用基于Spring代理的AOP的Spring应用程序。

当AnnotationTimeoutAspect暴露于Spring Application并使用时

对于Grails应用程序,设置为Config.groovygrails.spring.bean.packages=['com.xyz.aspect']或者对于Spring应用程序

引发以下错误。

解析切点时所需的参数名称不可用

当方面和切入点在单个类中实现时(没有抽象和具体的类),它会按预期工作。

当使用JUnit测试类和加载时编织进行本地测试时,抽象类和具体类的分离也可以很好地工作。当与基于Spring代理的AOP场景一起使用时,这一点不起作用。

我的目标是保持抽象方面的实现和具体方面的切入点,这样我就可以根据切入点的需要实现多个具体方面。

如果您有任何解决方法,请告诉我。

具体方面

@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";
}

抽象方面

@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);
}

错误

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

共有1个答案

廉志强
2023-03-14

抽象类中不能有@切入点。用所有切入点创建另一个类,并使其扩展这个类。建议可以留在这里。

 类似资料:
  • 来自spring参考文档 Spring建议您只使用@Transactional注释来注释具体的类(以及具体类的方法),而不是注释接口。您当然可以将@Transactional注释放置在接口(或接口方法)上,但只有在使用基于接口的代理时,它才会像您所期望的那样工作。Java注释不是从接口继承的,这意味着如果您使用的是基于类的代理(proxy-target-class=“true”)或基于编织的方面(

  • 我知道抽象类可能包含抽象和具体方法(即主体实现)。我的问题是:子类可以从抽象超类继承/覆盖具体方法吗?其次,它们必须以实现抽象方法的方式实现具体方法吗?

  • 在java中,是否可以使用通配符定义抽象方法,但在实现中使用具体类型 eg: 在这样的抽象类中定义抽象方法 实现如下抽象方法,其中CorporateServer扩展了用户:

  • 问题内容: 当其中的所有方法都是具体的时,有人在声明类抽象时有一些实际的编程情况吗? 问题答案: 好吧,您可能正在使用模板方法模式,其中存在多个都具有默认实现的覆盖点,但是组合的默认实现本身不合法-任何功能实现都必须是子类。 (是的,我不喜欢模板方法模式;)

  • 我在各自的字段中使用了@CreatedBy、@CreatedDate、@LastModifiedBy和@LastModifiedDate注释。通过使用@MappdSuperclass、@EntityListeners,我能够持久化上面的列。 但这不适用于以下情况: 审计员我mpl.java JpaAuditConfiguration。Java语言 在这种情况下,实体B填充了审计列。但实体A并非如此

  • 我想在我即将完成的一些工作中使用builder模式,它在一个层次结构中有几个类。基类将至少有9个字段要启动,各个子类可能会添加2-4个字段。这会很快失控,而builder模式正是出于这个原因吸引了我。我在书籍和文章中初步接触了builder模式。他们是有帮助的,但没有关于如何扩展这种模式。我试图自己实现这一点,但是我在每个子类的构造函数中遇到了麻烦,因为我不知道如何将构建器中收集的数据传递给超级类