AspectJ 切入点,用于采用可序列化或原始类型的任意数量参数的方法

AspectJ Pointcut for methods taking any number arguments of types Serializable or primitive type

我如何为采用任意数量的实现可序列化或原始类型的参数的方法编写切入点?

例如切入点应匹配:

methodA(String str, int i)
methodB(String str, String str2, List<String> list)

但不是

methodC(String str, DataX data)

其中 DataX 不可序列化

我不知道如何在切入点中指定那种条件,所以我唯一能为您提供的东西非常昂贵,因为它涉及运行时检查 - 但它可以满足您的要求:

驱动申请:

package de.scrum_master.app;

import java.io.Serializable;

public class Application {
    public static class MyNonSerializable {}

    public static class MySerializable implements Serializable {
        private static final long serialVersionUID = 1L;
    }

    private static MyNonSerializable one() {
        return new MyNonSerializable();
    }

    static MySerializable two(int i, String string) {
        return new MySerializable();

    }

    static String three(int i, String string, MyNonSerializable myNonSerializable) {
        return "foo";
    }

    static MyNonSerializable four(int i, String string, MySerializable mySerializable) {
        return new MyNonSerializable();
    }

    static void five(MyNonSerializable myNonSerializable) {
    }

    static int six(MySerializable mySerializable) {
        return 11;
    }

    public static void main(String[] args) {
        one();
        two(11, "foo");
        three(11, "foo", new MyNonSerializable());
        four(11, "foo", new MySerializable());
        five(new MyNonSerializable());
        six(new MySerializable());
    }
}

现在,无论 return 类型如何,我们都希望拦截带有零个参数或任意数量 Serializable 个参数的执行。符合这个条件的方法有main, one, two, four, six.

具有运行时类型检查的方面:

package de.scrum_master.aspect;

import java.io.Serializable;

public aspect MethodsWithSerializableArgumentsAspect {
    before() : execution(* *(..)) {
        boolean nonSerializableArgumentFound = false;
        for (Object arg : thisJoinPoint.getArgs()) {
            if (!(arg == null || arg instanceof Serializable)) {
                nonSerializableArgumentFound = true;
                break;
            }
        }
        if (nonSerializableArgumentFound)
            return;
        System.out.println(thisJoinPoint);
    }
}

控制台日志:

execution(void de.scrum_master.app.Application.main(String[]))
execution(Application.MyNonSerializable de.scrum_master.app.Application.one())
execution(Application.MySerializable de.scrum_master.app.Application.two(int, String))
execution(Application.MyNonSerializable de.scrum_master.app.Application.four(int, String, Application.MySerializable))
execution(int de.scrum_master.app.Application.six(Application.MySerializable))

太棒了! :-)

现在,如果您还想排除 returning 不可序列化对象的方法,则应将输出限制为 maintwosix。你可以这样做:

package de.scrum_master.aspect;

import java.io.Serializable;

public aspect MethodsWithSerializableArgumentsAspect {
    Object around() : execution(* *(..)) {
        boolean nonSerializableArgumentFound = false;
        for (Object arg : thisJoinPoint.getArgs()) {
            if (!(arg instanceof Serializable)) {
                nonSerializableArgumentFound = true;
                break;
            }
        }
        Object result = proceed();
        if ((result == null || result instanceof Serializable) && !nonSerializableArgumentFound)
            System.out.println(thisJoinPoint);
        return result;
    }
}

控制台日志:

execution(Application.MySerializable de.scrum_master.app.Application.two(int, String))
execution(int de.scrum_master.app.Application.six(Application.MySerializable))
execution(void de.scrum_master.app.Application.main(String[]))

请注意,为了对 return 值进行运行时检查,我们只能在 方法终止后 打印结果。因此,main 位于日志输出的末尾,而不是第一个解决方案中的开头。

更新: 我忘了解释为什么我们需要检查 null 的参数和 return 值。这是因为我们想接受nullvoidSerializable,但实际上null instanceof Serializable是假的


更新 2 - 没有运行时类型检查的静态切入点解决方案:

好吧,我刚刚在吃苹果(不,它没有掉到我头上),突然有这个想法。它实际上运行良好并且正是您想要的:

package de.scrum_master.aspect;

import java.io.Serializable;

public aspect MethodsWithSerializableArgumentsAspect {
    pointcut returnsSerializable() :
        execution((Serializable+ || byte || short || int || long || float || double || char || boolean || void) *(..));

    pointcut hasNonSerializableArguments() :
        execution(* *(.., !(Serializable+ || byte || short || int || long || float || double || char || boolean || void), ..));

    before() : returnsSerializable() && !hasNonSerializableArguments() {
        System.out.println(thisJoinPoint);
    }
}

顺便说一句,Serializable+ 表示 "Serializable and all of its subclasses or implementing classes"。

尽情享受吧!