AspctJ Aop 在Android中详细使用规则(二)

在上篇文章中,介绍了aspectJ的环境配置及简单的使用,接下来,我们来看详细的使用:

Pointcut 意思为切入点,我们知道,在面向对象编程中,我们可以使用反射和动态代理的方式来截取某个类中的某个方法,但是这样是比较损耗性能的,所以才有了aspectJ这样的插件诞生,使得我们不需要改变原来的代码结构即可在横向编程中增加自己的业务逻辑~

1、Join Point

先解释下Join Point, 作为连接点,需要告诉程序(Pointcut)需要切入的点在哪,在前一篇文章中,@Pointcut("within(com.makeramen.roundedimageview..*)") ,在官网中你回看到这样的写法:

aspect PointObserving {
    private Vector Point.observers = new Vector();

    public static void addObserver(Point p, Screen s) {
        p.observers.add(s);
    }
    public static void removeObserver(Point p, Screen s) {
        p.observers.remove(s);
    }

    pointcut changes(Point p): target(p) && call(void Point.set*(int));

    after(Point p): changes(p) {
        Iterator iter = p.observers.iterator();
        while ( iter.hasNext() ) {
            updateObserver(p, (Screen)iter.next());
        }
    }

    static void updateObserver(Point p, Screen s) {
        s.display(p);
    }
}

这样的写法Android编译器是不认识的,因为这是AspectJ编译器认识的写法,所以,我们需要将Join Point切入点写成字符串的方式来编译;我们来看下Join Point的规则,

Join Point 说明 Pointcuts语法
Method call 调用方法 call(MethodPattern)
Method execution 方法执行 execution(MethodPattern)
Constructor call 构造函数被调用 call(ConstructorPattern)
Constructor execution 构造函数执行 execution(ConstructorPattern)
Field get 读取属性 get(FieldPattern)
Field set 写入属性 set(FieldPattern)
Pre-initialization 与构造函数有关,很少用到 preinitialization(ConstructorPattern)
Initialization 与构造函数有关,很少用到 initialization(ConstructorPattern)
Static initialization static 块初始化 staticinitialization(TypePattern)
Handler 异常处理 handler(TypePattern)
Advice execution 所有 Advice 执行 adviceexcution()

这里,我们看到不同的切入点调用的Pointcuts方法也不同,这里先不作详细说明,下面会使用详细的例子来说明~

2、Pointcuts

在我们的例子中,使用了within这样的写法获取到某个包下的信息,这就是Pointcuts给我们带来的方便,他提供了多种写法给我们使用,让我们可以过滤到不需要的信息;下表中详细列出了使用方法:

Pointcuts语法 说明 示例
within(TypePattern) TypePattern标示package或者类TypePattern可以使用通配符 表示某个package或者类中的所有JPoint。比如within(Test):Test类中所有JPoint
withincode(Constructor Signature/Method Signature) 表示某个构造函数或其他函数执行过程中涉及到的JPoint 比如 withinCode(* TestDerived.testMethod(..)) 表示testMethod涉及的JPoint。withinCode( *.Test.new(..))表示Test构造函数涉及的JPoint
cflow(pointcuts) cflow是call flow的意思,cflow的条件是一个pointcut 比如cflow(call TestDerived.testMethod):表示调用TestDerived.testMethod函数时所包含的JPoint,包括testMethod的call这个JPoint本身
cflowbelow(Pointcut) cflow是call flow的意思 比如cflowblow(call TestDerived.testMethod):表示调用TestDerived.testMethod函数时所包含的JPoint,不包括testMethod的call这个JPoint本身
this(Type) Join Point 所属的 this 对象是否 instanceOf Type 或者 Id 的类型 JPoint是代码段(不论是函数,异常处理,static block),从语法上说,它都属于一个类。如果这个类的类型是Type标示的类型,则和它相关的JPoint将全部被选中。图2示例的testMethod是TestDerived类。所以this(TestDerived)将会选中这个testMethod JPoint
target(Type) JPoint的target对象是Type类型和this相对的是target。不过target一般用在call的情况。call一个函数,这个函数可能定义在其他类。 比如testMethod是TestDerived类定义的。那么target(TestDerived)就会搜索到调用testMethod的地方。但是不包括testMethod的execution JPoint
args(TypeSignature) 用来对JPoint的参数进行条件搜索的 比如args(int,..),表示第一个参数是int,后面参数个数和类型不限的JPoint。

Pointcut 表达式还可以 !、&&、|| 来组合,语义和java一样。上面 Pointcuts 的语法中涉及到一些 Pattern,下面是这些 Pattern 的规则,[]里的内容是可选的:

Pattern 规则
MethodPattern [!] [@Annotation] [public,protected,private] [static] [final] 返回值类型 [类名.]方法名(参数类型列表) [throws 异常类型]
ConstructorPattern [!] [@Annotation] [public,protected,private] [final] [类名.]new(参数类型列表) [throws 异常类型]
FieldPattern [!] [@Annotation] [public,protected,private] [static] [final] 属性类型 [类名.]属性名
TypePattern 其他 Pattern 涉及到的类型规则也是一样,可以使用 ‘!’、’‘、’..’、’+’,’!’ 表示取反,’‘ 匹配除 . 外的所有字符串,’*’ 单独使用事表示匹配任意类型,’..’ 匹配任意字符串,’..’ 单独使用时表示匹配任意长度任意类型,’+’ 匹配其自身及子类,还有一个 ‘…’表示不定个数。也可以使用 &&、|| 操作符

3、Pointcuts 语法

3.1 execution
3.1.1 execution 找类中方法
@Aspect
public class MethodApt {
    public static final String TAG = "AnnotationApt";
    @Pointcut("execution(* com.ellison.aop.method.ExcustionMethodActivity.test())")
    public void executionFindMethod() {
    }

    @Before("executionFindMethod()")
    public void invokMethod(JoinPoint point) throws Throwable {
        Log.d(TAG, "方法之前");
        ((ProceedingJoinPoint) point).proceed();
        Log.d(TAG, "方法之后");
    }
}

使用execution查找具体的某个类中的某个方法:

execution(* com.ellison.aop.method.ExcustionMethodActivity.test())

第一个 * 表示方法的修饰符,publicprivateprotected,上面解释了 * 为通配符,查找类下得所有方法:

execution(* com.ellison.aop.method.ExecutionMethodActivity.**())

具体的返回值、修饰符、方法查找就在上面的代码上修改即可~

3.1.2 execution 找注解

首先,我们编写一个自定义注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExecutionAnnotationFindMethod {
}

该注解使用在METHOD上,接下来我们编写aspectJ代码:

@Aspect
public class AnnotationApt {
    public static final String TAG = "AnnotationApt";
    @Pointcut("execution(@com...ExecutionAnnotationFindMethod * *(..))")
    public void annotationFindMethod() {
    }

    @Before("annotationFindMethod()")
    public void invokMethod(JoinPoint point) throws Throwable {
        Log.d(TAG, "具体方法之前");
        ((ProceedingJoinPoint) point).proceed();
    }
}

因为包名太长,所以我省略了,在Pointcut上,需要写上注解的包名全路径,很简单,我们需要给JoinPoint切入点写下如下代码即可:

execution(@com.ellison.aop.annotation_method.ExecutionAnnotationFindMethod * *(..))

写上注解的全路径,之后就是匹配 返回值方法名方法参数,例如你需要找到注解了ExecutionAnnotationFindMethod的方法,同时还需要找到返回值为ReturnParam的方法,则需要编写如下Pointcut:

execution(@com.ellison.aop.annotation_method.ExecutionAnnotationFindMethod ReturnParam *(..))

在比如,你需要找到参数为String类型的并注解了ExecutionAnnotationFindMethod的方法时,需要编写如下Pointcut:

execution(@com.ellison.aop.annotation_method.ExecutionAnnotationFindMethod * *(String))
3.2 within

看到within,想必大家都很熟悉;因为在我们第一个打印log的实例中就使用到了within 切入点包括 对象初始化块field构造方法方法

3.2.1 within 查找包下的任意连接点

首先,我们先定义一个简单的自定义view,这个自定义view就在它的中间区域内画一个圆,对,就是这么简单:

public class RoundedView extends View {

    private Context mContext;
    private Paint mPaint;

    public RoundedView(Context context) {
        this(context, null);
    }

    public RoundedView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundedView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mContext = context;
        initView();
    }

    private void initView() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.CYAN);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, 100, mPaint);
    }
}

初始化画笔paint之后,在onDraw()方法中直接使用canvas画圆即可,效果图如下:

within查找包下任意连接点.png

因为我们在Activity下使用了这个自定义view,所以下面我们开始使用within查找这个view所在的包下所有连接点并打印出方法、字段、构造函数:

@Aspect
public class WithinApt {

    public static final String TAG = "WithinApt";

    @Pointcut("within(com.ellison.aop.within..*)")
    public void withinFindPackage() {

    }

    @Before("withinFindPackage()")
    public void invokeMethod(JoinPoint joinPoint) throws Throwable {
        Log.d(TAG, "具体方法之前");
        ((ProceedingJoinPoint)joinPoint).proceed();
    }
}

上面,我们使用within找到了包下面所有的方法、字段、构造方法的连接切入点,

within(com.ellison.aop.within.*)

com.ellison.aop.within包下任意连接点

within(com.ellison.aop.within..*)

com.ellison.aop.within包或子包下任意连接点

within(RoundedView)

RoundedView类下的任意连接点

within(@com.xyz.service.BehavioClass *)

持有com.xyz.service.BehavioClass注解的任意连接点

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容