赞
踩
主要是记录学习 AOP
编程思想。项目中数据埋点统一方案有使用到,也是一次加深学习理解的过程。
AOP
是 Aspect-Oriented Programming
缩写,即面向切面编程。提倡针对同一类问题的统一处理方法。
AOP
这种编程思想有哪些作用呢?一般来说,主要用于不想侵入原有代码的场景中,例如SDK 需要无侵入的在宿主中插入一些代码,做日志埋点、性能监控、动态权限控制、甚至是代码调试等。
一个基于 AspectJ
并在此基础上扩展出来可应用于 Android
开发平台的 AOP
框架,可作用于java
源码,class
文件及 jar
包,同时支持 kotlin
的应用。
AspectJX
仅支持 annotation
的方式问:编译时会出现 can’t determine superclass of missing type** 及其他编译错误怎么办?
答:大部分情况下把出现问题相关的 class 文件或者库(jar 文件)过滤掉就可以搞定了
build.gradle
里依赖 AspectJX
。如下:dependencies {
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
app
模块的 build.gradle
里应用插件。如下:apply plugin: 'android-aspectjx'
AspectJX
配置AspectJX
默认会处理所有的二进制代码文件和库,为了提升编译效率及规避部分第三方库出现的编译兼容性问题,AspectJX
提供 include, exclude
命令来过滤需要处理的文件及排除某些文件(包括 class
文件及 jar
文件)。
配置在对应模块的 gradle
文件下,如下:
android{
aspectjx{
// 配置规则
}
}
示例配置如下:
aspectjx {
//排除所有package路径中包含`android.support`的class文件及库(jar文件)
exclude 'android.support'
}
aspectjx {
//忽略所有的class文件及jar文件,相当于AspectJX不生效
exclude '*'
}
更多详细规则使用自行查阅 Github AspectJX
框架相关知识了解。
gradle
中添加 dependencies
依赖。如下:dependencies {
implementation 'org.aspectj:aspectjrt:1.9.5'
}
java 8
android{
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
}
这样可以保证编译时不会报错异常,建议加上。到这里就完成了所有的配置,然后就可以愉快的 coding
MainActivity.java
中新增一个方法 void doAspectJX(String s)
,并在 onCreate
中调用,保证程序运行时能执行到这个方法。如下:@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
doAspectJX("");
}
private void doAspectJX(String s){
}
MyAspectJX.java
自定义类,然后在合适的时机切入。如下:@Aspect
public class MyAspectJX {
@After("execution(* *..MainActivity.doAspectJX*(..))")
public void test(JoinPoint point){
try {
MethodSignature methodSignature = (MethodSignature) point.getSignature();
String methodName = methodSignature.getName();
System.out.println(":> methodName: " + methodName);
}catch (Exception e){
e.printStackTrace();
}
}
几点说明:
@Aspect
注解进行标识示例中规则为:@After("execution(* *..MainActivity.doAspectJX*(..))")
表示:当程序执行完 MainActivity
类中的 doAspectJX()
这个方法之后进行切入。
更多规则同学们自行学习使用。
我们切入后,打印切入的方法名称。运行程序后打印结果如下:
上图所示,说明成功切入了,打印方法名称 doAspectJX
。
到这里就完成了从集成到简单应用的一个整体流程。
上面也谈到了 AOP
编程思想可用于埋点功能的实现,下面我们一起实现一下。
Behavior.java
。如下:public interface Behavior {
Map<String, Object> params();
}
这个接口,可以供需要埋点的类实现,然后通过实现 param()
方法,把需要埋点的参数和值保存到 map 中返回即可。
DataPoint.java
注解。如下:/**
* 自定义 DataPoint 注解
* 切入规则使用:仅标记方法
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataPoint {
}
使用注解来标记方法,可以很方便的指定切入规则,在合适时机进行切入获取数据,然后就可以愉快的上报数据了。
MainActivity.java
代码如下:// 实现 Behavior 接口 public class MainActivity extends AppCompatActivity implements Behavior{ Map<String, Object> map = new HashMap<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); doAspectJX(""); } @DataPoint private void doAspectJX(String s){ System.out.println(":> doAspectJX 执行"); map.put("name", "imxiaoqi"); } @Override public Map<String, Object> params() { return map; } }
MyAspectJX.java
代码如下:@Aspect public class MyAspectJX { // @After("execution(* *..MainActivity+.on*(..))") // @After("execution(* *..*.doAspectJX(..))") @After("execution(@DataPoint * *..*.*(..))") public void test(JoinPoint point){ try { // 获取被切入的类对象 // 示例中 MainActivity 实现了 Behavior 接口,故可以类型强转为 Behavior Behavior behavior = (Behavior) point.getThis(); // 获取数据,存于 Map 中 Map<String, Object> map = behavior.params(); System.out.println(":> 成功切入,获取 name: " + map.get("name")); }catch (Exception e){ e.printStackTrace(); } } }
@After("execution(@DataPoint * *..*.*(..))")
表示:任意类型 任意包下的任意类里的任意方法,并且方法添加了 DataPoint 注解,会在方法执行完后立即切入。
这样就会只在添加了注解的方法执行完后进行切入,可以对程序的整体性能影响降到最低。
上图所示,切入成功,数据也正常获取。
然后就可以愉快的将该数据埋点解决方案应用于项目中去了。
技术永不眠!我们下期见!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。