0.前言
本文基于上一篇上一篇的初步认识,进行一个简单的AOP实现。
本文目的:
AOP在android中的初步实践
Thanks:
主要参考
浅谈Android面向切面编程(AOP):
https://www.jianshu.com/p/aa1112dbebc7
该作者的gayhub:
https://github.com/GitLqr/AndroidAopDemo
其他资料
详解JDK 5 Annotation 注解之@Target的用法介绍
http://blog.csdn.net/snakemoving/article/details/74364351
@Retention注解
http://blog.csdn.net/asdgbc/article/details/70196749
1.集成AspectJ
app/build.gradle 内 添加(注意最顶上的import语句。):
...
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.8.1'
}
}
repositories {
mavenCentral()
}
android {
...
}
dependencies {
...
compile 'org.aspectj:aspectjrt:1.8.1'
}
final def log = project.logger
final def variants = project.android.applicationVariants
variants.all { variant ->
if (!variant.buildType.isDebuggable()) {
log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
return;
}
JavaCompile javaCompile = variant.javaCompile
javaCompile.doLast {
String[] args = ["-showWeaveInfo",
"-1.5",
"-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.定义一个自定义注解
package aroutertest.zj.com.zjaop.aspectj;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckLogin {
}
3.定义一个Aop切面
package aroutertest.zj.com.zjaop.aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* Created by thinkpad on 2018/2/8.
*/
@Aspect public class CheckLoginAspectJ {
String TAG = "CheckLoginAspectJ___";
// aroutertest.zj.com.zjaop.aspectj.CheckLogin
// * *(..)) 代表可以处理CheckLogin这个类所有的方法
@Pointcut("execution(@aroutertest.zj.com.zjaop.aspectj.CheckLogin * *(..))")
public void handleMethod() {
System.out.println(TAG + "@handleMethod");
}
@Before("handleMethod()")
public void before(JoinPoint point) {
System.out.println(TAG + "@Before");
}
@Around("handleMethod()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(TAG + "@Around");
// MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// String name = signature.getName(); // 方法名:test
// Method method = signature.getMethod(); // 方法:public void com.lqr.androidaopdemo.MainActivity.test(android.view.View)
// Class returnType = signature.getReturnType(); // 返回值类型:void
// Class declaringType = signature.getDeclaringType(); // 方法所在类名:MainActivity
// String[] parameterNames = signature.getParameterNames(); // 参数名:view
// Class[] parameterTypes = signature.getParameterTypes(); // 参数类型:View
// TestAnnoTrace annotation = method.getAnnotation(TestAnnoTrace.class);
// String value = annotation.value();
// int type = annotation.type();
// long beginTime = SystemClock.currentThreadTimeMillis();
joinPoint.proceed();
// long endTime = SystemClock.currentThreadTimeMillis();
// long dx = endTime - beginTime;
// System.out.println("耗时:" + dx + "ms");
}
@After("handleMethod()")
public void after(JoinPoint point) {
System.out.println(TAG + "@After");
}
@AfterReturning("handleMethod()")
public void afterReturning(JoinPoint point, Object returnValue) {
System.out.println(TAG + "@AfterReturning");
}
@AfterThrowing(value = "handleMethod()", throwing = "ex")
public void afterThrowing(Throwable ex) {
System.out.println(TAG + "@afterThrowing");
System.out.println("ex = " + ex.getMessage());
}
}
4.添加测试代码
这俩方法是mainactivity内的俩按钮的点击事件。
@CheckLogin()
public void percheck(View view) {
System.out.println("Hello, I am 权限检查");
}
@CheckLogin()
public void logincheck(View view) {
System.out.println("Hello, I am 登录检查");
}
5.测试观察打印
点击按钮,输入如下。
I/System.out: CheckLoginAspectJ___@Before
I/System.out: CheckLoginAspectJ___@Around
I/System.out: Hello, I am 权限检查
I/System.out: CheckLoginAspectJ___@After
I/System.out: CheckLoginAspectJ___@AfterReturning
预警:
关于这个AspectJ,当我们定义了多个切点时,很有可能因为一个切点的表达式写错而导致编译出错,从而让其他的切点失效,所以玩的时候出错了的话,尽量将gradle consle打开。
6.Demo
https://github.com/zj614android/AopDemo
更新
studio升级之后,若gradle是3.+的,1.x的aspectj就不好使了,aspectj目前已经更新到2.0.2,我也提到本文github了,路过的同学可以去down下来参照着改,地址还是这个https://github.com/zj614android/AopDemo
PPS:这是项目作者地址,我是根据这个来改好的:
https://github.com/HujiangTechnology/AspectJX-Demo