使用aspectj拦截带有反射

时间:2017-04-15 03:54:49

标签: java reflection aop aspectj

当我使用tomcat运行应用程序时,它表示该建议尚未被应用,因此我的方面将无效。我必须在任何地方配置吗?我没有做任何事情,所以我不知道哪些代码可能有用。

谢谢!

修改

我刚刚发现了如何解决这个问题,即使它说方面尚未应用,当我调用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;
    }
}

我有这堂课:

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

有没有拦截那个?谢谢!

1 个答案:

答案 0 :(得分:1)

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

实际上你不需要通过obj绑定第一个参数args(),我只是用它来记录,以便向你展示那里发生的事情。所以这个稍微简单的形式也会这样做:

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的更改包含在我的叉子中的另一个pull request中。