使用 aspectj 拦截带反射的赋值

Using aspectj to intercept an assignment with reflection

当我 运行 带有 tomcat 的应用程序时,它说建议没有被应用,所以我的方面将无法工作。我必须在任何地方配置它吗?我没有做任何事情,所以我不知道什么代码可能有用。

谢谢!

编辑

我刚刚发现如何解决这个问题,即使它说尚未应用方面,当我调用 setter 时它仍然有效,但我在使用反射时遇到问题那。

我有一个方面可以将 setter 拦截到一个工作正常的字段,但是当从示例中的 Gson 库分配值时,它不起作用。

这是方面:

public aspect AnnotationAspect {

    pointcut hasAnnotation(Annotation annotation) : @annotation(annotation);

    Object around(Annotation annotation, String word) : hasAnnotation(annotation) && set(String *) && args(word) {
        Object result = null;
        try {
            result = proceed(annotation, "intercepted");
        } catch (RuntimeException ex) {
            throw ex;
        }
        return result;
    }
}

我有这个 class:

public class JavaEntity {

    @Annotation
    public String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

当我这样做时,它不会拦截赋值:

JavaEntity entity = new Gson().fromJson("{\"name\":\"name\"}", JavaEntity.class);

有办法拦截吗?谢谢!

反射字段访问不能被AspectJ直接拦截。您只能通过以毒攻毒来解决它,即也使用反射:

  • 确保 Gson 在 AspectJ 编译器的 inpath 上(即 AspectJ Maven 插件的编织依赖项),以便能够编织到其代码中。
  • 拦截对 Field.set(..).
  • 的调用
  • 在拦截通知中检查要设置哪个字段,通过反射查找其注解以模仿@annotation(blah),决定是否修改其值。

这不完全是通常的 AspectJ 用例,但有可能。

顺便说一句,execution() 连接点没有这种问题,因为它们也会在反射调用方法时触发。不过,call() 会有问题。但这只是供您参考,与这个具体案例没有直接关系。


更新:我的意思是这样的:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <configuration>
        <weaveDependencies>
            <weaveDependency>
                <groupId>Group</groupId>
                <artifactId>model</artifactId>
            </weaveDependency>
            <weaveDependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
            </weaveDependency>
        </weaveDependencies>
    </configuration>
</plugin>
@Test
public void testingInterceptWithJavaGson(){
    javaEntity = new Gson().fromJson("{\"name\":\"newName\"}", JavaEntity.class);
    Assert.assertEquals("intercepted", javaEntity.getName());
}
Object around(Field field, Object obj, Object value) :
    within(com.google.gson..*) &&
    call(public void Field.set(Object, Object)) &&
    target(field) &&
    args(obj, value)
{
    Object result = null;
    System.out.println(thisJoinPoint);
    System.out.println("  " + field + " -> " + field.getAnnotation(Annotation.class));
    System.out.println("  " + obj);
    System.out.println("  " + value);
    try {
        if (field.getAnnotation(Annotation.class) != null && field.getType() == String.class)
            result = proceed(field, obj, "intercepted");
        else
            result = proceed(field, obj, value);
    } catch (RuntimeException ex) {
        throw ex;
    }
    return result;
}

其实你不需要通过args()绑定第一个参数obj,我只是用它来记录日志,以便向你展示那里发生了什么。所以这个稍微简单一点的形式也可以:

Object around(Field field, Object value) :
    within(com.google.gson..*) &&
    call(public void Field.set(Object, Object)) &&
    target(field) &&
    args(*, value)
{
    Object result = null;
    System.out.println(thisJoinPoint);
    try {
        if (field.getAnnotation(Annotation.class) != null && field.getType() == String.class)
            result = proceed(field, "intercepted");
        else
            result = proceed(field, value);
    } catch (RuntimeException ex) {
        throw ex;
    }
    return result;
}

我的分支对您现有 GitHub repo are contained in yet another pull request 的更改。