AspectJ 基础

 前两篇AspectJ入门的文章大致的介绍了AspectJ,本文更完整、更详细的介绍AspectJ的基础知识。包括了切点、连接点、类型间声明及thisJoinPoint的基础知识,来更好的理解AspectJ的语法。

1 切点和连接点

挑选切点的时候,我们还可以通过方法的访问权限、是否是static来区分,同时也能挑选出接口的方法:

public aspect PointPickAspect {
    pointcut staticPoint(): call(static * article.service.PointPick.*(..));
    pointcut privatePoint(): call(private * article.service.PointPick.*(..));
    pointcut interfacePoint(): call(* article.service.CustomInterface.*(..)); // CustomInterface是接口

    before(): staticPoint() || privatePoint() || interfacePoint() {
        System.out.println();
        System.out.println(thisJoinPoint.toLongString());
    }
}

1.1 call 与 execution

call:获取调用签名时的连接点。在实际开发中会用到。

execution:获取代码段在运行时的连接点。通常用于跟踪调试。

call 与 execution对于within 或withincode的匹配方式也不同。

public class ExecutionAndCall {

    static void fun(int num) {
        System.out.println(num);
        System.out.println();
        if (num > 0) fun(--num);
    }

    public static void main(String[] args) {
        ExecutionAndCall.fun(4);
    }

}

public aspect ExecutionAndCallAspect {

    pointcut callPoint(): call(void article.service.ExecutionAndCall.fun(..)) &&
    withincode(void article.service.ExecutionAndCall.fun(..)); // 切点是:fun中递归调用的fun连接点

    pointcut executionPoint(): execution(void article.service.ExecutionAndCall.fun(..));
       // 注意execution 的连接点严格意义来说不在fun方法体内,所以加上:
       // && withincode(void article.service.ExecutionAndCall.fun(..)) 将匹配不到任何连接点

    before(): callPoint() {
        System.out.println("-----callPoint-----");
        System.out.println(thisJoinPointStaticPart.getSignature());
        System.out.println(thisJoinPointStaticPart.getSourceLocation());
    }

    before(): executionPoint() {
        System.out.println("----executionPoint----");
        System.out.println(thisJoinPointStaticPart.getSignature());
        System.out.println(thisJoinPointStaticPart.getSourceLocation());
    }

}

1.2 切点类型

分类指示符

选择连接点的特定种类,如:call、execution、hander、get、set

作用域指示符

选择一组连接点。with及withincode

上下文指示符

基于上下文匹配,可选择地绑定的指示符。如 this、target、args、@annotation

表 切点类型

作用域指示符匹配速度非常快,它们可以非常快速地消除不应该进一步处理的连接点组。

所以好的切点标准是,至少包括作用域指示符和分类指示符。

2 类型间声明

AspectJ 可以为类声明及定义成员(字段、方法和构造器),还可以为类实现新的接口或者继承新的类型。

在AspectJ 中为类定义的成员,如果其访问权限运行,可以在类中及切面中使用。

private

只限于当前切面访问(被定义的类中也不能访问)。就是在其他切面或这个类也定义了同名的属性,也不会互相干扰。

default

包访问权限。在这个切面所在包下的切面及类可以访问。可能会发生同名冲突。

public

任何切面或者类都可以访问,可能会发生同名冲突。

表 Aspect类型间声明支持的访问权限

还可以定义类新的构造器。

public class InterEntityParent {
    void sayByFather() {
        System.out.println("InterEntityParent 父级");
    }
}

public class InterEntity {

    private int x = 0;

    public void setX(int x) {
        this.x = x;
    }

    public int getX() {
        return x;
    }

    public static void main(String[] args) {
        InterEntity interEntity = new InterEntity(99); // 当前类并未定义该构造器,但是在切面中定义了
        interEntity.show();
//        interEntity.sayByFather(); // 编码时虽红字提示,但是能运行,在切面中为该类继承了InterEntityParent
    }
//    运行结果:
//    [email protected]:99
//    同时可以访问到同包下,为该类定义的default访问类型变量:InterEntityAspect定义的属性
//    InterEntityParent 父级
}

public aspect InterEntityAspect {

    interface InterEntityAspectInterface {
        void show();
    }

    private int InterEntity.x = 99; // InterEntity 中已存在x,但这里定义private并不会冲突

    String InterEntity.defaultVal = "InterEntityAspect定义的属性"; // 在当前切面所在包下的任何切面或类可以访问

    declare parents: InterEntity implements InterEntityAspectInterface; // 在InterEntity中或者切面中必须为其实现show方法,否则编译错误

    declare parents: InterEntity extends InterEntityParent; // 让InterEntity继承InterEntityParent

    public InterEntity.new(int num1) { // 定义InterEntity 构造器
        this.setX(num1); // this 指的是InterEntity的实例
    }

}

public aspect InterEntityAspect2 {
    public void InterEntity.show() { // 为InterEntity定义show方法
        System.out.println(this + ".x:" + this.getX());
        System.out.println("同时可以访问到同包下,为该类定义的default访问类型变量:" + this.defaultVal);
    }
}

3 thisEnclosingJoinPointStaticPart

封闭连接点的静态部分。不是当前连接点,是封闭连接点。可以使用这个来打印出调用的原位置。

public class EnclosingJoinPointEntity {
    public void fun1() { // enclosePoint 连接点的封闭节点
        System.out.println("fun1");
        System.out.println("---");
        fun2(); // enclosePoint 的连接点
    }

    public void fun2() {
        System.out.println("fun2");
        System.out.println("---");
    }

    public static void main(String[] args) {
        EnclosingJoinPointEntity entity = new EnclosingJoinPointEntity();
        entity.fun1();
    }
}

public aspect EnclosingJoinPointEntityAspect {
    pointcut enclosePoint(): call(* article.service.EnclosingJoinPointEntity.fun2(..));

    before(): enclosePoint() {
        System.out.println("thisJoinPoint");
        System.out.println(thisJoinPoint);
        System.out.println(thisJoinPoint.getSourceLocation());
        System.out.println("--------------");
        System.out.println("thisEnclosingJoinPointStaticPart");
        System.out.println(thisEnclosingJoinPointStaticPart);
        System.out.println(thisEnclosingJoinPointStaticPart.getSourceLocation());
        System.out.println();
    }
}

你可能感兴趣的:(Spring,java,开发语言,spring)