介绍:
AspectJ是一款面向切面(AOP)的第三方框架,当在AseptJ环境下编译java代码的时候,将使用ajc来替换javac编译,所以Asept是在编译期间就改变了代码结构。
配置:
1. 首先添加maven仓库路径:
在项目的build.gradle中加入以下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| buildscript { repositories { google() jcenter() mavenCentral() } dependencies { classpath "com.android.tools.build:gradle:4.1.2" classpath 'org.aspectj:aspectjtools:1.9.6' classpath 'org.aspectj:aspectjweaver:1.9.6' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } }
|
2. 在module的build.gradle里添加以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| import org.aspectj.bridge.IMessage import org.aspectj.bridge.MessageHandler import org.aspectj.tools.ajc.Main android { ··· ···
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.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; } } } } }
dependencies {
···
implementation files('libs/aspectjrt.jar') //或者 // implementation 'org.aspectj:aspectjrt:1.9.6'
}
|
3. 创建注解类IFirstAnnotation
@Target 注解目标,表示注解使用在什么地方,这里是METHOD方法;@Retention 保留策略,表示注解调用时机,这里RUNTIME运行时
1 2 3 4 5
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface IFirstAnnotation { String value(); }
|
4. 创建切面类MethodBehaviorAspect
自定义注解行为
@Aspect指定切面类;@Pointcut切入点;@Around是切入方式Advice的一种,表示在切入点前后插入代码,还有@Before、@After;Pointcut语法,execution,表示根据Advice在执行方法内部代码前后插入代码,call,表示根据Advice在调用方法前后插入代码......
@pointcut(execution(@全类名 * *(. .)))
后面的两个表示*匹配所有的方法名,两个.表示匹配所有的方法参数.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| @Aspect public class MethodBehaviorAspect { private static final String TAG = "aspect_aby";
@Pointcut("execution(@com.test.qby.aspectjlib.annotation.IFirstAnnotation * *(..))") public void firstMethodAnnotationBehavior() { }
@Pointcut("execution(* com.test.qby.newtestapplication.ui.MainActivity.aspectClick(android.view.View))") public void secondMethodAnnotationBehavior() { }
@Around("firstMethodAnnotationBehavior()") public Object wavePointcutAround(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); // 类名 String className = methodSignature.getDeclaringType().getSimpleName(); // 方法名 String methodName = methodSignature.getName(); // 功能名 IFirstAnnotation behaviorTrace = methodSignature.getMethod() .getAnnotation(IFirstAnnotation.class); String value = behaviorTrace.value(); // String value = "点击"; long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); long duration = System.currentTimeMillis() - start; Log.e(TAG, String.format("%s类中%s方法执行%s功能,耗时:%dms", className, methodName, value, duration)); Toast.makeText(getContext(joinPoint.getThis()), String.format(Locale.CHINESE, "%s类中%s方法执行%s功能,耗时:%dms", className, methodName, value, duration), Toast.LENGTH_SHORT).show(); return result; }
/** * 通过对象获取上下文 * @param o o * @return c */ private Context getContext(Object o) { if (o instanceof Activity) { return (Activity) o; } else if (o instanceof Fragment) { Fragment fragment = (Fragment) o; return fragment.getContext(); } else if (o instanceof View) { View view = (View) o; return view.getContext(); } return null; } }
|
5. 页面调用
@IFirstAnnotation调用注解,()内部为在IFirstAnnotation中写的value的值,去掉value()后此处去掉()
1 2 3 4 5 6 7 8
| @IFirstAnnotation("测试Aspect") public void aspectClick(View view) { try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } }
|