(4.6.23.2)Android之面向切面编程:Aspect集成示例之DebugTrace 与 SecurityCheckAnnotation
来源:互联网 发布:淘宝开店培训班 编辑:程序博客网 时间:2024/05/21 17:51
- 一集成方法一
- 二集成方法二
- 三DebugTrace
- 1 定义注解DebugTrace
- 1 计时工具类
- 3 切面编程
- 四SecurityCheckAnnotation
- 1 定义注解
- 2 定义切面
- 参考文献
一、集成方法一
- 需要在项目根目录的build.gradle中增加依赖:
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.0-beta2' classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:1.0.10' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }}
- 再主项目或者库的build.gradle中增加AspectJ的依赖
compile 'org.aspectj:aspectjrt:1.8.9'同时在build.gradle中加入AspectJX模块apply plugin: 'android-aspectjx'
这样就把整个Android Studio中的AspectJ的环境配置完毕了,如果在编译的时候,遇到一些『can’t determine superclass of missing type xxxxx』这样的错误,请参考项目README中关于excludeJarFilter的使用。
aspectjx { //includes the libs that you want to weave includeJarFilter 'universal-image-loader', 'AspectJX-Demo/library' //excludes the libs that you don't want to weave excludeJarFilter 'universal-image-loader'}
二、集成方法二
- AspectJ比较强大,除了支持对source文件(即aj文件、或@AspectJ注解的Java文件,或普通java文件)直接进行编译外,
- 还能对Java字节码(即对class文件)进行处理。有感兴趣的同学可以对aspectj-test小例子的class文件进行反编译,你会发现AspectJ无非是在被选中的JPoint的地方加一些hook函数。当然Before就是在调用JPoint之前加,After就是在JPoint返回之前加。
- 更高级的做法是当class文件被加载到虚拟机后,由虚拟机根据AOP的规则进行hook。
在Android里边,我们用得是第二种方法,即对class文件进行处理:
//AndroidAopDemo.build.gradle //此处是编译一个App,所以使用的applicationVariants变量,否则使用libraryVariants变量 //这是由Android插件引入的。所以,需要import com.android.build.gradle.AppPlugin; android.applicationVariants.all { variant -> /* 这段代码之意是: 当app编译个每个variant之后,在javaCompile任务的最后添加一个action。此action 调用ajc函数,对上一步生成的class文件进行aspectj处理。 */ AppPluginplugin = project.plugins.getPlugin(AppPlugin) JavaCompile javaCompile = variant.javaCompile javaCompile.doLast{ String bootclasspath =plugin.project.android.bootClasspath.join(File.pathSeparator) //ajc是一个函数,位于utils.gradle中 ajc(bootclasspath,javaCompile) } }
ajc函数其实和我们手动试玩aspectj-test目标一样,只是我们没有直接调用ajc命令,而是利用AspectJ提供的API做了和ajc命令一样的事情。
import org.aspectj.bridge.IMessage import org.aspectj.bridge.MessageHandler import org.aspectj.tools.ajc.Main def ajc(String androidbootClassFiles,JavaCompile javaCompile){ String[] args = ["-showWeaveInfo", "-1.8", //1.8是为了兼容java 8。请根据自己java的版本合理设置它 "-inpath",javaCompile.destinationDir.toString(), "-aspectpath",javaCompile.classpath.asPath, "-d",javaCompile.destinationDir.toString(), "-classpath",javaCompile.classpath.asPath, "-bootclasspath", androidbootClassFiles] MessageHandlerhandler = new MessageHandler(true); new Main().run(args,handler) deflog = project.logger 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 throw message.thrown break; case IMessage.WARNING: case IMessage.INFO: log.info message.message, message.thrown break; case IMessage.DEBUG: log.debug message.message, message.thrown break; } } }
主要利用了https://eclipse.org/aspectj/doc/released/devguide/ajc-ref.html中TheAspectJ compiler API一节的内容。由于代码已经在csdn git上,大家下载过来直接用即可。
三、DebugTrace
有该注解的函数,打印执行时间
3.1 定义注解DebugTrace
/** * Indicates that the annotated method is being traced (debug mode only) and * will use {@link android.util.Log} to print debug data: * - Method name * - Total execution time * - Value (optional string parameter) */@Retention(RetentionPolicy.CLASS)@Target({ ElementType.CONSTRUCTOR, ElementType.METHOD })public @interface DebugTrace {}
4.1 计时工具类
public class TimeWatcher { private long startTime; private long endTime; private long elapsedTime; public TimeWatcher() { //empty } private void reset() { startTime = 0; endTime = 0; elapsedTime = 0; } public void start() { reset(); startTime = System.nanoTime(); } public void stop() { if (startTime != 0) { endTime = System.nanoTime(); elapsedTime = endTime - startTime; } else { reset(); } } public long getTotalTimeMillis() { return (elapsedTime != 0) ? TimeUnit.NANOSECONDS.toMillis(endTime - startTime) : 0; } public long getStartTime() { return startTime; } public long getEndTime() { return endTime; }}
3.3 切面编程
/** * 类描述: * Aspect representing the cross cutting-concern: Method and Constructor Tracing. * Created by yhf on 2017/3/28. */@Aspectpublic class DebugTraceAspect { public static final String TAG = "MainActivity-DTAspect"; //有这个注解的 返回值任意的 所有类的所有函数且参数不限 private static final String POINTCUT_METHOD = "execution(@com.sangfor.aop.annotation.DebugTrace * *(..))"; //有这个注解的 返回值任意的 所有类的构造函数且参数不限 private static final String POINTCUT_CONSTRUCTOR = "execution(@com.sangfor.aop.annotation.DebugTrace *.new(..))"; @Pointcut(POINTCUT_METHOD) public void methodAnnotatedWithDebugTrace() {} @Pointcut(POINTCUT_CONSTRUCTOR) public void constructorAnnotatedDebugTrace() {} @Around("methodAnnotatedWithDebugTrace() || constructorAnnotatedDebugTrace()") public Object debugTraceJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); String className = methodSignature.getDeclaringType().getSimpleName(); String methodName = methodSignature.getName(); final TimeWatcher stopWatch = new TimeWatcher(); stopWatch.start(); Object result = joinPoint.proceed(); stopWatch.stop(); LogCore.aspectI(TAG, new TimeAspectData("DebugTraceAspect","debugTraceJoinPoint",joinPoint,stopWatch).toString()); return result; //修改这里,相当于hook了返回值 }}
几个在此提到的重点:
- 我们声明了两个作为 pointcuts 的 public 方法,筛选出所有通过 “org.android10.gintonic.annotation.DebugTrace” 注解的方法和构造函数。
- 我们使用 “@Around” 注解定义了 “weaveJointPoint(ProceedingJoinPoint joinPoint)” 方法,使我们的代码注入在使用 “@DebugTrace” 注解的地方生效。
- “Object result = joinPoint.proceed();” 这行代码是被注解的方法执行的地方。因此,在此之前,我们启动我们的计时类计时,在这之后,停止计时。
- 最后,我们构造日志信息,用 Android Log 输出。
@DebugTrace private int mapGUI() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } testAOP(); return 1; }
四、SecurityCheckAnnotation
检查权限
4.1 定义注解
//第一个@Target表示这个注解只能给函数使用//第二个@Retention表示注解内容需要包含的Class字节码里,属于运行时需要的。@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface SecurityCheckAnnotation {//@interface用于定义一个注解。 public String declaredPermission(); //declarePermssion是一个函数,其实代表了注解里的参数}
4.2 定义切面
@Aspectpublic class SecurityCheckAnnotationAspect { public static final String TAG = "MainActivity-SCAAspect"; /* 来看这个Pointcut,首先,它在选择Jpoint的时候,把@SecurityCheckAnnotation使用上了,这表明所有那些public的,并且携带有这个注解的API都是目标JPoint 接着,由于我们希望在函数中获取注解的信息,所有这里的poincut函数有一个参数,参数类型是SecurityCheckAnnotation,参数名为ann 这个参数我们需要在后面的advice里用上,所以pointcut还使用了@annotation(ann)这种方法来告诉AspectJ,这个ann是一个注解 */ @Pointcut("execution(@com.sangfor.aop.annotation.SecurityCheckAnnotation * *(..)) && @annotation(securityCheckAnnotation)") public void checkPermssion(SecurityCheckAnnotation securityCheckAnnotation){}; /* 接下来是advice,advice的真正功能由check函数来实现,这个check函数第二个参数就是我们想要 的注解。在实际运行过程中,AspectJ会把这个信息从JPoint中提出出来并传递给check函数。 */ @Before("checkPermssion(securityCheckAnnotation)") public void checkPermssionByAspect(JoinPoint joinPoint, SecurityCheckAnnotation securityCheckAnnotation){ //从注解信息中获取声明的权限。 String neededPermission = securityCheckAnnotation.declaredPermission(); Log.d(TAG, "checkPermssionByAspect--" + joinPoint.toShortString()); Log.d(TAG, "checkPermssionByAspect -- \tneeded permission is " + neededPermission); return; }}
参考文献
- 深入理解Android之AOP
- 看AspectJ在Android中的强势插入
0 0
- (4.6.23.2)Android之面向切面编程:Aspect集成示例之DebugTrace 与 SecurityCheckAnnotation
- (4.6.23.3)Android之面向切面编程:Aspect示例之继承关系测试
- (4.6.23.1)Android之面向切面编程:AOP 与 Aspect简介
- aspect 面向切面编程
- 面向切面编程之研究与探讨
- 面向切面编程(AOP:Aspect Orient Programming)1
- 面向切面编程(AOP:Aspect Orient Programming)2
- spring面向切面编程AOP(Aspect-orented programming)
- AOP(面向切面编程 Aspect Oriented Programming)
- Spring aop(Aspect Oriented Programming:面向切面编程)入门
- Java 面向切面编程(Aspect Oriented Programming,AOP)
- Spring之AOP(面向切面编程)
- Spring之AOP(面向切面编程)
- Spring之配置切面aspect
- AOP面向切面编程(Aspect Oriented Programming)
- 面向切面编程 Aspect Oriented Programming
- AOP( aspect-oriented programming)面向切面编程
- Aspect-Oriented Programming 面向切面编程
- Framework7中Template7的使用
- 完全背包多重背包模板
- Java Web 之过滤器Filter详解
- sensor输出四种类型:YUV ,RGB ,RAW RGB ,JPEG
- Qt实现Trackball交互方式代码
- (4.6.23.2)Android之面向切面编程:Aspect集成示例之DebugTrace 与 SecurityCheckAnnotation
- Qt元系统之类型注册
- java如何将网页表格导出为excel
- PHP循环遍历数组的3种方法list()、each()和while总结
- easyui tabs 在同一个页面中打开多个tab多页面中变量名或函数名重复问题
- Deep Learning(深度学习)学习笔记整理系列之(二)
- 基于QualComm的mmc driver解析(Kernel-3.10)——(1)mmc bus
- synchronized与volatile的区别
- Oracle 常见的执行计划步骤(explain结果的Description数据参考)