android AOP面向切面编程---AspectJ使用

以下内容仅为个人学习记录

一、配置AspectJ

方法一

使用github上开源的SDK

(1)在项目根目录的build.gradle里依赖AspectJX

dependencies {
        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'
        }

(2)在app项目的build.gradle里应用插件

apply plugin: 'android-aspectjx'
//或者这样也可以
apply plugin: 'com.hujiang.android-aspectjx'

以上就完成了配置,以下是一些额外配置

aspectjx {
    //排除所有package路径中包含`android.support`的class文件及库(jar文件)
    exclude 'android.support'
    // 或者织入遍历符合条件的库
    include 'android.support'
    
    //关闭AspectJX功能
    enabled false
}

方法二

(1)自行配置,新建一个gradle文件。然后在app项目的build.gradle引入

// aspectj 编译所需gradle脚本
apply from: 'aspectj-configure-app.gradle'

至于aspectj-configure-app.gradle的内容,大家可以查看项目中的该文件

(2)导入aspectj库的依赖

api 'org.aspectj:aspectjrt:1.8.10'

二、 使用AspectJ

(1)新建一个类,在类顶部加上@Aspect注解

@Aspect
public class TestAspect {
}

(2)编写切入点

~下面的例子就是代表切入点为Activity的onCreate方法

execution(protected void android.app.Activity.onCreate(Bundle))
execution()--用于描述方法
protected--修饰符,“*”代表任意(可省略)
void--返回值类型,“*”代表任意(不能省略)
android.app.Activity.onCreate--完整的方法引用名
(Bundle)--参数类型,多参数用逗号隔开如(int, int);“”代表任意参数,如(, int),即代表第一个参数任意,第二个为整型。
(..) : 这个写法就代表任意个数的参数,任意类型

~所以下面的写法是包含上面的例子

execution(* android.app.Activity.onCreate(..))

~完整的方法引用名使用通配符的写法

android.app.Activity.* -- 该类下任意的方法名
java.io.Serializable+.* -- 实现该接口的类下任意的方法名
android.app.*.* -- 该android.app包下任意类的任意方法名
android.app..*.* -- 该android.app包和其子包下任意类的任意方法名
android.app..Activity.* -- 该android.app包和其子包下所有名字叫Activity的类的任意方法名

~方法名也可以使用通配符

on* -- 以on开头的方法名
*Create -- 以Create结尾的方法名
on*Create -- 以on开头和Create结尾,中间包含任意字符的方法名

~组合切入点表达式

||或运算(符合方法1或方法2)
execution(* android.app.Activity.onCreate(..)) || execution(* android.app.Activity.onResume(..))
&& 且运算(同时实现接口1和接口2)
execution(* (cn.javass.IPointcutService+&& java.io.Serializable+).*(..))
!非运算(除了指定方法以外的方法)
execution(* (!cn.javass..IPointcutService+).*(..))

~使用@Pointcut注解辅助编写切入点

    private static final String POINTCUT_METHOD =
            "execution(* on*Click(..))";
    private static final String POINTCUT_BUTTER_KNIFE =
            "execution(@butterknife.OnClick * *(..))";

    @Pointcut(POINTCUT_METHOD)
    public void methodPointcut() {

    }

    @Pointcut(POINTCUT_BUTTER_KNIFE)
    public void butterKnifePointcut() {

    }

    @Around("methodPointcut() || butterKnifePointcut()")
    public void aroundJoinPoint(ProceedingJoinPoint joinPoint) {
        
    }

以上是比较常用的expression表达式写法,至于还有一些复杂的用法和写法可以参考这篇文章link

(3)AspectJ通知类型(切入时机)

@Before(前置通知)-- 在方法执行前执行

@After(最终通知)-- 方法执行完毕后执行,无论方法中是否出现异常

@Around(环绕通知)-- 替换原有的逻辑,原有逻辑是否继续进行,或是取消,取决于我们@Around方法下的逻辑

@AfterReturning(后置通知)-- 方法正常返回后执行,如果方法中抛出异常,通知无法执行必须在方法执行后才执行,所以可以获得方法的返回值。

@AfterThrowing (抛出异常通知)-- 方法抛出异常后执行,如果方法没有抛出异常,无法执行

    @Before("……")
    public void onMethodBefore(JoinPoint joinPoint){
    }
    
    @After("……")
    public void onMethodAfter(JoinPoint joinPoint){
    }
    
    @Around("……")
    public void onMethodArounde(ProceedingJoinPoint joinPoint){
      joinPoint.proceed(); // 执行原有逻辑
    }
    
    @AfterReturning(value = "……", returning="result")
    public void onMethodAfterReturning(Object result){
    }
    
    @AfterThrowing(value = "……", throwing="ex")
    public void onMethodAfterThrowing(Exception ex){
    }

(4)JoinPoint类介绍

~JoinPoint

Object[] getArgs():获取连接点方法运行时的入参列表
Object getTarget():获取连接点所在的目标对象
String toShortString():获取该目标对象方法命名

~ProceedingJoinPoint(继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法)

Object proceed() throws Throwable:通过反射执行目标对象的连接点处的方法
Object proceed(Object[] args) throws Throwable:通过反射执行目标对象连接点处的方法,不过使用新的入参替换原来的入参

三、项目申请权限的AOP使用

    @RequestPermission(permissions = {Manifest.permission.CAMERA})
    public void startImageCapture(……) {
        
    }
    
    @RequestPermission(requestCode = 100, permissions = {Manifest.permission.CAMERA}, hint = "相机打开失败,没有权限!")
    public void startImageCapture(……) {
        
    }
    
    // 拒绝权限
    @RequestPermissionRefuse
    public void refusePermission(int requestCode) {
        
    }
    
    // 禁止权限
    @RequestPermissionForbid
    public void forbidPermission(int requestCode) {
        
    }
    

AspectJ的API文档

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

推荐阅读更多精彩内容