AspectJ

什么是AspectJ?

AspectJ实际上是对AOP编程思想的一个实践,它是一种几乎和Java完全一样的语言,而且完全兼容Java。但是编译时得用Aspect专门的编译器,使用时必须配置Aspect的编译器,单独加入aspectj依赖是不行的。

使用AspectJ有两种方法:

  • 完全使用AspectJ的语言。这语言一点也不难,和Java几乎一样,也能在AspectJ中调用Java的任何类库。AspectJ只是多了一些关键词罢了。

  • 使用纯Java语言开发,然后使用AspectJ注解,简称@AspectJ。

切点表达式

1,execution

execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
注意:execution的粒度为方法,也就是说是匹配方法的
除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。

  1. 修饰符模式: 如 public private protected

  2. 返回类型模型: 如 String Object 等

  3. 方法名模型: 如 traceOnClickView

  4. 参数模型: 如Params

  5. 异常模型: 如ClassNotFoundException

  6. ? 表示非必选

  execution(*  *..MainActivity.on*(..))
  • 第一个 * :表示方法的任意返回类型;

  • *..:表示省略了MainActivity的包名,当然这里也可以写出完整包名;

  • on*表示MainActivity中所有以on开头的方法;

  • (..):表示方法的参数可以是任意类型且个数任意

精确地匹配到Person类里的eat()方法

@Before("execution(* com.zx.aop1.Person.eat())")

匹配Person类里的所有方法,可以使用通配符。

@Before("execution(* com.zx.aop1.Person.*(..))")

第一个*表示返回值为任意类型,第二个*表示这个类里的所有方法,()括号表示参数列表,括号里的用两个点号表示匹配任意个参数,包括0个。

2,within

within(<type name>)
接口、类名、包名

匹配com.zx.aop1.person.Student类中的所有方法

    @Pointcut("within(com.zx.aop1.person.Student)")

匹配com.zx.aop1.person包及其子包中所有类中的所有方法

    @Pointcut("within(com.zx.aop1.person..*)")

匹配com.zx.aop1.person.Person类及其子类的所有方法

    @Pointcut("within(com.zx.aop1.person.Person+)")

匹配所有实现com.zx.aop1.person.Human接口的类的所有方法,包括接口方法和实现类的额外方法

@Pointcut("within(com.zx.aop1.person.Human+)")

3,便捷的方式获取参数

可以通过joinPoint.getArgs()的方式去拿方法参数。

 @Pointcut(value = "execution(* com.zx.aop1.MainActivity.testArgs(..))")
    private void pc2(){}

    /**
     * 通过JoinPoint连接点的方式去拿方法参数
     * @param joinPoint
     */
    @Before("pc2()")
    public void testArgs2(JoinPoint joinPoint){
        for (Object arg : joinPoint.getArgs()) {
            Log.e(TAG, "testArgs2---: "+arg );
        }
    }

4,@annotation

匹配使用了CheckAop注解的方法

    @Pointcut(value = "@annotation(checkAop)")
    private void aAnnotation2(CheckAop checkAop) {
    }

    @After("aAnnotation2(checkAop)")
    public void testaAnnotation2(CheckAop checkAop) {
        Log.e(TAG, "testaAnnotation2---: "+checkAop.value() );
    }

//还有这种 方式,两种方式是等价的
   @Pointcut("@annotation(com.zx.aop1.CheckAop)")
    private void aAnnotation1() {
    }

 @After("aAnnotation1()")
    public void testaAnnotation(JoinPoint joinPoint) {
    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        CheckAop checkAop = method.getAnnotation(CheckAop.class);
        Log.e(TAG, "testaAnnotation--: "+checkAop.value() );
    }

匹配所有实现Human接口的类的所有方法且方法的第一个参数为int类型

@Pointcut("within(com.zx.aop1.person.Human+) && execution(* com.zx.aop1.person...* *(int,..))")

ProceedingJoinPoint

ProceedingJoinPoint是JoinPoint的子接口,该对象只用在@Around的切面方法中

    @Around("execution(* *..MainActivity.testAOP())")
    public void onActivityMethodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        String key = proceedingJoinPoint.getSignature().toString();
        Log.e(TAG, "onActivityMethodAroundFirst: before " + key + "do something");
        //执行原方法
        proceedingJoinPoint.proceed();
        Log.e(TAG, "onActivityMethodAroundSecond: after " + key + "do something");
    }

关键点在于proceed()方法,有没有发现,这个流程不就是代理模式吗?

/**
 * ProceedingJoinPoint exposes the proceed(..) method in order to support around advice in @AJ aspects
 *
 * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
 */
public interface ProceedingJoinPoint extends JoinPoint {

    /**
     * 执行目标方法 
     *
     * @return
     * @throws Throwable
     */
    public Object proceed() throws Throwable;

    /**
     * 传入的新的参数去执行目标方法 
     *
     * @param args
     * @return
     * @throws Throwable
     */
    public Object proceed(Object[] args) throws Throwable;

}

(AspectJ)的基本原理

大白话解释:通常在做aspectj编程的时候,会定义切面@Aspect,在切面中会定义@Pointcut(切点)和Advice(通知),最后编译的时候aspectj的ajc编译器会把通知方法的逻辑代码加入到切点方法前后。当然其他JoinPoint也是可以的,比如变量访问,抛出异常等。

案例

先来看一个简单的案例,在Activity生命周期方法打印日志

@Aspect
public class AspectTest {
    private static final String TAG = AspectTest.class.getSimpleName();

    @Before("execution(* com.zx.aop2.MainActivity.on*(..))")
    public void testLog(JoinPoint joinPoint){
        MethodSignature methodSignature= (MethodSignature) joinPoint.getSignature();
        Log.e(TAG, "testLog---: "+methodSignature.getMethod().getName() );
    }
}

下面看一下编译后的.class文件反编译之后的效果:

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.runtime.reflect.Factory;

public class MainActivity extends AppCompatActivity {
    public MainActivity() {
    }

    protected void onCreate(Bundle savedInstanceState) {
        JoinPoint var2 = Factory.makeJP(ajc$tjp_0, this, this, savedInstanceState);
        AspectTest.aspectOf().testLog(var2);
        super.onCreate(savedInstanceState);
        this.setContentView(2131427356);
    }

    static {
        ajc$preClinit();
    }
}

可以看出,我们的目标文件已经发生了变化。由于我们在切面@Aspect中是定义了在切点方法执行之前打印日志,这里的切点方法就是onCreate(),而这个方法的内容也确实如我们预想的一样,在执行onCreate()之前(也就是super之前)插入了我们的通知方法的代码。

利用aspectjx不仅可以修改项目class,还可以操作jar和aar的class。

感谢

深入理解Android之AOP

Aspect Oriented Programming in Android

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

推荐阅读更多精彩内容