Andorid Studio中配置AspectJ
app module中
dependencies {
implementation 'org.aspectj:aspectjrt:1.9.4'
}
project module中
buildscript {
dependencies {
classpath 'org.aspectj:aspectjtools:1.9.4'
}
}
如果需要在AspectJ中打印日志还需要在app module中结尾添加如下代码
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.9",
"-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;
}
}
}
}
使用@Before做登录验证
定义一个验证登录的注解
package com.xxx.xxx.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//登录验证
@Target(ElementType.METHOD)//作用域为方法
@Retention(RetentionPolicy.RUNTIME)//范围运行时
public @interface UserLogin {
String value();
}
实现一个切面类,用于拦截上面所写的注解切面
package com.xxx.xxx.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* Describe : 验证登录的切面
* 若要使用aspectj,需要在类上标记@Aspect
*/
@Aspect
public class UserLoginAspect {
//定义切面的规则
//@Pointcut 表示一个切入点
//格式:execution(@注解的全路径 注解用的地方)
//这里表示注解UserLogin下的所有方法都会被该切入点拦截
@Pointcut("execution(@com.xxx.xxx.annotation.UserLogin * *(..))")
public void methodAnnottatedWithUserLogin() {
}
//处理切面内容,指向哪个切入点
//@Before 在切入点之前运行
//@After 在切入点之后运行
//@Around 在切入点前后都运行
@Before("methodAnnottatedWithUserLogin()")
public Object checkLogin(ProceedingJoinPoint joinPoint) throws Throwable {
if (isLogin()) {//在进入某个方法之前,先判断是否登录
toLogin();//如果没有登录则去登陆,不再继续往下执行该方法
return null;
} else {//如果登录则继续往下执行该方法
Object result = joinPoint.proceed();//继续执行方法
return result;
}
}
}
使用该切面
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@UserLogin("测试登录控制")
public void onAspcetJByLogin(View view) {
//需要登录才能执行的逻辑
}
}
使用@Around实现性能监控
定义一个性能监控的注解
package com.xxx.xxx.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//性能跟踪
@Target(ElementType.METHOD)//作用域为方法
@Retention(RetentionPolicy.RUNTIME)//范围运行时
public @interface BehaviorTrace {
String value();
}
package com.xxx.xxx.aspect;
import android.util.Log;
import com.xxx.xxx.annotation.BehaviorTrace;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
/**
* Describe : 性能切面类
* 若要使用aspectj,需要在类上标记@Aspect
*/
@Aspect
public class BehaviorAspect {
//定义切面的规则
//1、就再原来的应用中那些注解的地方放到当前切面进行处理
//execution(注解名 注解用的地方)
@Pointcut("execution(@com.xxx.xxx.annotation.BehaviorTrace * *(..))")
public void methodAnnottatedWithBehaviorTrace() {
}
//处理切面内容
//@Before 在切入点之前运行
//@After 在切入点之后运行
//@Around 在切入点前后都运行
@Around("methodAnnottatedWithBehaviorTrace()")
public Object checkBehaviorTrace(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//获取名为login()的方法
Method loginMethod=methodSignature.getReturnType().getMethod("login");
//获得类名
String className = methodSignature.getDeclaringType().getSimpleName();
//获得当前拦截的方法名
String methodName = methodSignature.getName();
//获得当前拦截的方法名上标记的注解中的vaule的值
String value = methodSignature.getMethod().getAnnotation(BehaviorTrace.class).value();
//在这里计算当前被拦截的方法所消耗的时间
long begin = System.currentTimeMillis();
Object result = joinPoint.proceed();//方法继续执行
long duration = System.currentTimeMillis() - begin;
Log.d("alan", String.format("%s功能:%s类的%s方法执行了,用时%d ms",
value, className, methodName, duration));
return result;
}
}
使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@BehaviorTrace("检测性能")
public void onAspcetJByBehaviorTrace(View view) {
//测试性能,这里使主线程睡5s之内随机的时间,模拟一个耗时操作
SystemClock.sleep(new Random().nextInt(5000));
}
}
使用@After做行为日志记录
创建行为日志记录的注解
package com.xxx.xxx.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Describe:用户行为日志记录
*/
@Target(ElementType.METHOD)//作用域为方法
@Retention(RetentionPolicy.RUNTIME)//范围运行时
public @interface CourseLog {
//当前记录来自于哪个用户
String userId();
}
实现日志记录的切面
package com.xxx.xxx.aspect;
import android.util.Log;
import com.xxx.xxx.annotation.CourseLog;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
/**
* Describe: 用户行为日志记录切面
*/
@Aspect
public class CouresLogAspect {
@Pointcut("execution(@com.xxx.xxx.annotation.CourseLog * *(..))")
public void getCouresLog() {
}
@After("getCouresLog()")
public Object checkCouresLog(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//获得类名
String className = methodSignature.getDeclaringType().getSimpleName();
//获得当前拦截的方法名
String methodName = methodSignature.getName();
//调用时间
long createTime = System.currentTimeMillis();
//获得当前拦截的方法名上标记的注解中的userid
String userid = methodSignature.getMethod().getAnnotation(CourseLog.class).userId();
//这里相当于将这条行为日志上传,这里只是打印出来
Log.d("alan", String.format("%s类的%s方法在%l时间被%s用户调用了",
className, methodName, createTime, userid));
return null;
}
}
使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@CourseLog(userId = "uid_123456")
public void onAspectJByCourseLog(View view) {
//用户调用了该方法后就会上传一条记录
}
}