背景
现在一提到aspectj,大家都是想到aspectjx这个别人封装好的插件,确实也很好用,只要在项目下grade文件添加下面几行代码就可以了:
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8' //project的bulid.gradle
apply plugin: 'android-aspectjx' // 使用 AspectJX 插件 module 的bulid.gradle
api 'org.aspectj:aspectjrt:1.8.13' //在依赖里面 module 的bulid.gradle
然后就可以美滋滋的写aspect切面文件了
*但是对于android library(不是一个app)这种情况,这个插件是不适用的,因为里面规定了只扫描编译成app的class *
所以我使用了原生的aspectj来完成这种情况的注入,鉴于现在查到的资料都比较老,所以写一下这个笔记给有需要的人,也防止我忘了,本文章不涉及有关知识的讲解仅仅是操作,详细了解可以看后面的链接(或者哪天有空更新下,大概)。
一 操作步骤
(1) 配置环境
- 在project的build.grade添加依赖
classpath 'org.aspectj:aspectjweaver:1.9.4'
- module 的bulid.gradle添加以下代码
implementation 'org.aspectj:aspectjrt:1.8.13' //依赖里面
//然后找个下面空的地方复制下面的代码进去,下面的代码主要是替换成ajc编译器,
//android.libraryVariants.all表示会
//扫描android library的class,就是这里让注入第三方库可以成功
//如果是想扫描app的换成android.applicationVariants.all
//
apply plugin: 'com.android.library' //如果没有记得加上这句
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
final def log = project.logger
android.libraryVariants.all{ variant ->
JavaCompile javaCompile = variant.javaCompiler
javaCompile.doLast {
String[] args = ["-showWeaveInfo",
"-1.8",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
log.debug "ajc args: " + Arrays.toString(args)
MessageHandler handler = new MessageHandler(true)
new Main().run(args, handler)
for (IMessage message : handler.getMessages(null, true)) {
switch (message.getKind()) {
case IMessage.ABORT:
case IMessage.ERROR:
case IMessage.FAIL:
log.error message.message, message.thrown
break
case IMessage.WARNING:
log.warn message.message, message.thrown
break
case IMessage.INFO:
log.info message.message, message.thrown
break
case IMessage.DEBUG:
log.debug message.message, message.thrown
break
}
}
}
}
(2) 写切面文件
aspect 切面
在编译时,由编译器把切面调用编译进字节码,这种方式需要定义新的关键字并扩展 编译器,AspectJ就扩展了Java编译器,使用关键字aspect来实现织入。所以第一步要做的就是新建一个java文件,在类名上面加上注解@aspect,这表示这是一个切面文件,ajc编译器会识别这个注解按照规则进行代码的织入。类似下面:
@Aspect //①
public class MethodAspect {
@Pointcut("call(* com.wandering.sample.aspectj.Animal.fly(..))")//②
public void callMethod() {
}
@Before("callMethod()")//③
public void beforeMethodCall(JoinPoint joinPoint) {
Log.e(TAG, "before->" + joinPoint.getTarget().toString()); //④
}
}
piontcut 切点
如上图的这行代码就定义了一个切点
@Pointcut("call(* com.wandering.sample.aspectj.Animal.fly(..))")//②
具体怎么定义还是上github上大神总结的规则
advice
总结
AOP是Aspect Oriented Programming,即面向切面编程。OOP:Object Oriented Programming,面向对象编程。OOP的主要功能是数据封装、继承和多态,而AOP提供了一种新的视角,AOP把系统分解为不同的关注点,或者称之为切面(Aspect),如打印日志,权限检查等都可以使用AOP方式让代码更加简洁,业务代码更加明确。
参考文章
Android AspectJ详解
AOP面向切面编程,AspectJ在Android中应用二三事(上)
AspectJ In Android Studio
原生aspectj原理解析
sample_aspectj