2017年09月20日
AOP(Aspect Oriented Programming),中文通常翻译成面向切面编程。在Java当中我们常常提及到的是OOP(Object Oriented Programming)面向对象编程。其实这些都只是编程中从不同的思考方向得出的一种编程思想、编程方法。 在开发过程中,对于很多场景可以借助AOP来完成,比如日志监控,异常处理,无侵入的在宿主中插入一些代码等。这里有一篇博文介绍的非常详细《深入理解Android之AOP》,感兴趣的可以深入阅读一下~
本文主要从实践层面来学习下AspectJ的使用,以及实际项目中中,可以给程序开发带来的方便。
AspectJ的配置
1、工程根目录build.gradle配置
buildscript {
...
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'org.aspectj:aspectjtools:1.8.6'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
...
2、app目录下build.gradle配置
import org.aspectj.bridge.IMessage // 添加aspectj的相关类
import org.aspectj.bridge.MessageHandler // 添加aspectj的相关类
import org.aspectj.tools.ajc.Main // 添加aspectj的相关类
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId "com.xyzlf.aspectjdemo"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.+'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile 'org.aspectj:aspectjrt:1.8.6' // 添加aspectj的依赖
}
//-------------------------------------------
//-----------------添加如下代码----------------
//-------------------------------------------
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;
}
}
}
}
代码编写
1、自定义切片,在People类的static静态代码块执行完成后,打印一句话。
2、自定义Pointcut && 组合Pointcut, 对MainActivity中的crash进行处理。
package com.xyzlf.aspectjdemo;
import android.util.Log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* Created by zhanglifeng on 2017/9/20.
*/
@Aspect
public class TestAspect {
public static final String TAG = "TestAspect";
//@After,表示使用After类型的advice,里面的value其实就是一个poincut
@After(value = "staticinitialization(*..People)")
public void afterStaticInitial(){
Log.d(TAG,"the static block is initial");
}
@Pointcut(value = "handler(Exception)")
public void handleException(){
}
@Pointcut(value = "within(*..MainActivity)")
public void codeInMain(){
}
// 这里通过&&操作符,将两个Pointcut进行了组合
// 表达的意思其实就是:在MainActivity当中的catch代码块
@Before(value = "codeInMain() && handleException()")
public void catchException(JoinPoint joinPoint){
Log.d(TAG,"this is a try catch block. " + joinPoint.toString());
}
}
编译后MainActivity类和People类信息
1、MainActivity
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.xyzlf.aspectjdemo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.xyzlf.aspectjdemo.People;
import com.xyzlf.aspectjdemo.TestAspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.runtime.reflect.Factory;
public class MainActivity extends AppCompatActivity {
public MainActivity() {
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(2130968603);
new People();
this.test("this is tag for test");
}
public void test(String test) {
try {
throw new IllegalArgumentException("self throw exception");
} catch (Exception var5) {
JoinPoint var4 = Factory.makeJP(ajc$tjp_0, this, (Object)null, var5);
TestAspect.aspectOf().catchException(var4);
}
}
static {
ajc$preClinit();
}
}
2、People:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.xyzlf.aspectjdemo;
import com.xyzlf.aspectjdemo.TestAspect;
public class People {
public People() {
}
static {
try {
boolean var0 = true;
} catch (Throwable var2) {
if(var2 instanceof ExceptionInInitializerError) {
throw (ExceptionInInitializerError)var2;
}
TestAspect.aspectOf().afterStaticInitial();
throw var2;
}
TestAspect.aspectOf().afterStaticInitial();
}
}
运行程序后日志
09-20 03:56:56.672 10847-10847/? D/TestAspect: the static block is initial
09-20 03:56:56.672 10847-10847/? D/TestAspect: this is a try catch block.)
[ 09-20 03:56:56.694 10847:10847 D/ ]
HostConnection::get() New Host Connection established 0xe0cb1280, tid 10847
Demo地址
地址:https://github.com/xyzlf/AspectjDemo
参考资料
1、Android AOP学习之:AspectJ实践:https://juejin.im/post/58ad3944b123db00672cdeeb
2、看 AspectJ 在 Android 中的强势插入:https://juejin.im/post/587989f48d6d810058bbae01
3、深入理解Android之AOP:http://blog.csdn.net/innost/article/details/49387395