前两篇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
    }
//    运行结果:
//    article.service.InterEntity@2a84aee7.x: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();
    }
}


