AspectJ指示符@args()在Spring AOP中不起作用 [英] AspectJ designator @args() not working in Spring AOP

查看:488
本文介绍了AspectJ指示符@args()在Spring AOP中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习Spring,并且搜索了很多有关如何正确使用@args()AspectJ指示符的信息,但是我仍然不清楚.我所知道的是,它将联合匹配限制为方法的执行,这些方法的参数使用给定的注释类型进行注释.就我而言,这似乎不起作用.

I am learning Spring and I searched a lot about how to properly use @args() AspectJ designator but I am still not clear completely. What I know about it is that it limits joint-point matches to the execution of methods whose arguments are annoted with the given annotation types. This does not seem to work in my case.

这是我的文件:

Human.java

@Component
public class Human {
    int sleepHours;
    public int sleep(String sleepHours) {
        this.sleepHours = Integer.parseInt(sleepHours);
        System.out.println("Humans sleep for " + this.sleepHours + " hours.");
        return this.sleepHours+1;
    }
}

Sleepable.java -睡眠注释

 package com.aspect;
 public @interface Sleepable {

 }

SleepingAspect.java -方面

@Component
@Aspect
public class SleepingAspect {

    @Pointcut("@args(com.aspect.Sleepable)")
    public void sleep(){};

    @Before("sleep()")
    public void beforeSleep() {
        System.out.println("Closing eyes before sleeping");
    }

    @AfterReturning("sleep()")
    public void afterSleep() {
        System.out.println("Opening eyes after sleep");
    }
}

MainApp.java

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Human human = (Human) context.getBean("human");
        @Sleepable
        String sleepHours = "8";
        human.sleep(sleepHours);
    }
}

输出

人类睡了8个小时.

预期产量

睡觉前闭上眼睛

人类睡了8个小时.

睡后睁开眼睛

推荐答案

您的代码有几个错误:

  • Spring AOP只能拦截对Spring组件的方法调用.您要拦截的是在局部变量上的注释.甚至功能更强大的AspectJ都不能拦截与局部变量有关的任何内容,而只能拦截对类成员的读/写访问.因此,您试图做的事情是不可能的.顺便说一句,这是糟糕的应用程序设计.为什么有人在尝试应用跨领域行为时想依靠方法内部?方法内部经常进行重构.建议:将注释放在方法public int sleep(String sleepHours)上.
  • 您的注释在运行时不可见,因为您忘记添加像@Retention(RetentionPolicy.RUNTIME)这样的元注释.
  • @args是错误的切入点类型.它捕获方法自变量的类型.您想改用@annotation(com.aspect.Sleepable).
  • Spring AOP can only intercept method calls upon Spring components. What you are trying to intercept is an annotation on a local variable. Not even the much more powerful AspectJ can intercept anything concerning local variables, only read/write access to class members. Thus, what you are trying to do is impossible. And by the way, it is bad application design. Why would anyone want to rely on method internals when trying to apply cross-cutting behaviour? Method internals are subject to frequent refactoring. Suggestion: Put your annotation on method public int sleep(String sleepHours).
  • Your annotation is invisible during runtime because your forgot to add a meta annotation like @Retention(RetentionPolicy.RUNTIME).
  • @args is the wrong pointcut type. It captures method arguments the types of which are annotated. You want to use @annotation(com.aspect.Sleepable) instead.

我认为您不应该尝试复制&从Spring AOP开始粘贴冷启动,但请阅读 Spring AOP手册.我在这里解释的所有内容都可以在此处找到.

I think you should not try a copy & paste cold start with Spring AOP but read the Spring AOP manual first. Everything I explained here can be found there.

更新:因此,根据您的评论,您只是在练习并尝试构成@args()的示例.这是一个简单的AspectJ.您可以在Spring AOP中以类似的形式轻松使用它. @Before建议显示了如何在带有其类注释的参数上进行匹配,@After建议还显示了如何将相应的注释绑定到建议参数上.

Update: So according to you comments you were just practicing and trying to make up an example for @args(). Here is one in plain AspectJ. You can easily use it in similar form in Spring AOP. The @Before advice shows you how to match on an argument with an annotation on its class, the @After advice also shows how to bind the corresponding annotation to an advice argument.

使用它的注释+类:

package com.company.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

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

package com.company.app;

@MyAnnotation
public class MyClass {}

驱动程序应用程序:

package com.company.app;

public class Application {
  public static void main(String[] args) {
    new Application().doSomething(new MyClass(), 11);
  }

  public String doSomething(MyClass myClass, int i) {
    return "blah";
  }
}

如您所见,这里我们在方法参数中使用带注释的类MyClass.在以下方面,可以将其与@args()匹配.

As you can see, here we use the annotated class MyClass in a method argument. This can be matched with @args() in the following aspect.

方面:

package com.company.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import com.company.app.MyAnnotation;

@Aspect
public class MyAspect {
  @Before("@args(com.company.app.MyAnnotation, ..)")
  public void myBeforeAdvice(JoinPoint thisJoinPoint) {
    System.out.println("Before " + thisJoinPoint);
  }

  @After("@args(myAnnotation, ..)")
  public void myAfterAdvice(JoinPoint thisJoinPoint, MyAnnotation myAnnotation) {
    System.out.println("After " + thisJoinPoint + " -> " + myAnnotation);
  }
}

控制台日志:

Before call(String com.company.app.Application.doSomething(MyClass, int))
Before execution(String com.company.app.Application.doSomething(MyClass, int))
After execution(String com.company.app.Application.doSomething(MyClass, int)) -> @com.company.app.MyAnnotation()
After call(String com.company.app.Application.doSomething(MyClass, int)) -> @com.company.app.MyAnnotation()

当然,call()连接点在Spring AOP中不可用,因此在那里您只会看到两行日志输出.

Of course, call() joinpoints are unavailable in Spring AOP, so there you would only see two lines of log output.

这篇关于AspectJ指示符@args()在Spring AOP中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆