面向切面编程-Aspect Oriented Programming,简称AOP,通过预编译的方式和运行期间动态代理实现程序功能的统一维护的一种技术。
AOP能够做什么呢?
- 性能检测
- 权限验证
- 释放资源
- 用户行为统计
这个技术当进行性能调优的时候特别好用,配置好了只需要添加一个注解就能控制是否需要输入耗时等信息,特别容易控制,快来看看如何配置吧。
那么AOP如何使用呢?
前期准备工作
1.在主工程的build.gradle增加编译配置
//增加编译规则
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.8.8'
classpath 'org.aspectj:aspectjweaver:1.8.8'
}
}
//为了方便看到日志输出
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
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;
}
}
}
}
2.然后在libs 下面添加 aspectjrt.jar
下面进入是具体实现
- 定义一个注解,用来标识哪些是需要统计的。
- 将相应的注解添加到需要统计的方法上
- 定义切面规则
- 在原来应用中的哪些注释的地方放到切面进行处理
- 对进入切面的内容如何处理
现在有这样一个需求,客户要求统计轮廓线各个特效的耗时情况
- 获取轮廓线耗时
- 单独矢量化的耗时
- 矢量化后增加单色渲染耗时
- 矢量化后增加渐变色颜色耗时
- 矢量化+粉笔+单色耗时
- 矢量化+粉笔+渐变色耗时
- 线条矢量化+荧光笔+单色耗时
- 线条矢量化+荧光笔+渐变色耗时
- 线条矢量化+单色渲染+网点耗时
- 线条矢量化+单色渲染+排线耗时
如果不采用AOP,就需要在方法前后添加时间戳,copy很多重复的代码才可以,下面通过AOP来处理。
3.定义一个注解类
@Target(ElementType.METHOD) //使用在方法上
@Retention(RetentionPolicy.RUNTIME) //到运行期间都要存在
public @interface BehaviorTrace {
String value();
}
用来标识哪些地方需要统计性能标识
4.标识需要统计性能的方法
/**
* 对图片进行矢量化
*/
@BehaviorTrace("矢量化操作")
public void vectorBitmap() {
if (mLineBitmap == null) {
Log.e("meicam", "mLineBitmap is null");
return;
}
String lineJsonStr = mImageEffectContext.getVectorDataFromImage(mLineBitmap, -0.6f);
mVectBitmap = mImageEffectContext.renderVectorEffect(mLineBitmap, lineJsonStr, mSrcImageWidth, mSrcImageHeight);
ivImage.setImageBitmap(mLineBitmap);
}
/**
* 渐变色
*/
@BehaviorTrace("渲染渐变色")
private void gradientColor() {
if (mVectBitmap == null) {
Log.e("meicam", "mLineBitmap is null");
return;
}
Bitmap bmp = mImageEffectContext.renderColorEffect(mVectBitmap, Color.RED,
Color.WHITE,
Color.GREEN, mSrcImageWidth, mSrcImageHeight, true, false);
ivImage.setImageBitmap(bmp);
}
像上面这个方式标记需要统计的方法
3.写切面类
@Aspect
public class BehaviorAspect {
//切面规则
//1.在原来的应用中哪些注释的地方放到切面上
@Pointcut("execution(@com.meishe.imageshow.annotation.BehaviorTrace * *(..))")
public void fromBehaviorTrace(){}
//2.对进行切面的进行处理
//@Before 触发之前调用
//@After 触发之后调用
//@Around 触发期间调用
@Around("fromBehaviorTrace()")
public Object joinPoint(ProceedingJoinPoint joinPoint) throws Throwable{
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //方法签名
String methodName = signature.getName(); //方法名
String className = signature.getDeclaringType().getName();
String value = signature.getMethod().getAnnotation(BehaviorTrace.class).value();
//统计时间
long beginTime=System.currentTimeMillis();
Object proceed = joinPoint.proceed();
long duration=System.currentTimeMillis()-beginTime;
Log.d("lpf",String.format("%s-->%s-->%s-->耗时%d ms",className,methodName,value,duration));
return proceed;
}
}
上面是实际项目中的两个方法,我分析耗时的一个配置方式。
这样就可以输出对图片进行矢量化方法的耗时以及渐变色的耗时了,这里的数据也可以写入到本地文件,推送到服务器等。如果想测试其他方法的耗时直接在方法中添加 @BehaviorTrace 这个注解就可以了,赶紧配置来试试吧……