以下内容仅为个人学习记录
一、配置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) {
}