1.Aspect用戶行為統計
他不生成代碼,他是生產的搬運工去做行為統計
AOP切面編程
在AOP術語體系中,切面真正要做的工作稱之為通知(advice)。
Spring切面支持以下五種通知:
Before——前置通知,在調用目標方法之前執行通知定義的任務;
After——后置通知,在目標方法執行結束后,無論執行結果如何都執行通知定義的任務;
After-returning——后置通知,在目標方法執行結束后,如果執行成功,則執行通知定義的任務;
After-throwing——異常通知,如果目標方法執行過程中拋出異常,則執行通知定義的任務;
Around——環繞通知,在目標方法執行前和執行后,都需要執行通知定義的任務。
注解的方式寫類,集成方便用戶行為統計
動態代理AspectJ,遵循java編譯原則,編譯修改后的java,class文件
Step
1、創建AS原工程
Step
如下圖,app看到的,這個就是我們的業務主項目,下面aspectj就是第二步要做的。
2、創建module(Android Library),然后添加AspectJ依賴,必須添加至module中,添加至APP工程中ajc編譯器是不會重構目標代碼的。
把所有的切面的東西寫這個module 里面獨立出來,吧aspectjrt.jar放這個lib西面
首先我們要新建一個自己的注解類在annotation的包下,新建一個BehaviorTrace用戶行為統計
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//存在于什么時期
//CLASS存在于class中
//RUNTIME是在運行時有效
@Retention(RetentionPolicy.RUNTIME)
//使用在普通方法和構造方法上
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
/**
* 標志該行為需要被統計
* @author Administrator
*
*/
public @interface BehaviorTrace {
String value();
}
然后開始定義自己的切面在aspect包下新建一個自定義的切面
import java.lang.annotation.Annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import com.jason.aop.annotation.BehaviorTrace;
import android.util.Log;
/**
* 用戶行為統計的切面
* @author Administrator
*
*/
@Aspect
public class BehaviorAspect {
//定義切面的規則
//1.通俗來講就是切面長什么樣?哪些方法在這個切面上,哪些功能需要被統計
//2.切面上方法執行,需要進行什么樣的處理
//只要帶有BehaviorTrace注解的方法,都屬于我這個切面
@Pointcut("execution(@com.jason.aop.annotation.BehaviorTrace * *(..))")
public void methodAnnotatedWithBehaviorTrace(){}
//只要帶有BehaviorTrace注解的方法任何類的任何構造方法都是屬于我的切面
@Pointcut("execution(@com.jason.aop.annotation.BehaviorTrace *.new(..))")
public void constructorAnnotatedWithBehaviorTrace(){}
//環繞
@Around("methodAnnotatedWithBehaviorTrace() || constructorAnnotatedWithBehaviorTrace()")
public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable{
//joinPoint 切點,面由點構成
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//這個切點是哪個類的哪個方法
String className = methodSignature.getDeclaringType().getSimpleName();
String methodName = methodSignature.getName();
BehaviorTrace behaviorTrace = (BehaviorTrace)methodSignature.getMethod().getAnnotation(BehaviorTrace.class);
String funName = behaviorTrace.value();
//sprintf
//統計執行耗時時間
long begin = System.currentTimeMillis();
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - begin;
Log.d("jason", String.format("功能:%s,%s 的? %s 方法執行,耗時:%d ms",funName,className,methodName,duration));
return result;
}
}
這樣就可以了,
下面說說如何配置添加 AspectJ編譯
3.
編寫build腳本,添加任務,使得IDE使用ajc作為編譯器編譯代碼。這樣就可以了
build.gradle(app):
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.8.9'
}
}
apply plugin: 'com.android.application'
repositories {
mavenCentral()
}
dependencies {
compile project(':aspectjlibrary')
}
android {
compileSdkVersion 21
buildToolsVersion '22.0.1'
buildTypes {
debug {
minifyEnabled false? // should disable proguard in debug builds
}
}
defaultConfig {
applicationId "com.example.lingyimly.try2"
minSdkVersion 15
targetSdkVersion 21
}
lintOptions {
abortOnError true
}
}
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.5",
"-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;
}
}
}
}
build.gradle(module):
import com.android.build.gradle.LibraryPlugin
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
apply plugin: 'com.android.library'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'org.aspectj:aspectjtools:1.8.9'
classpath 'org.aspectj:aspectjweaver:1.8.9'
}
}
repositories {
mavenCentral()
}
dependencies {
compile 'org.aspectj:aspectjrt:1.8.9'
compile 'com.android.support:appcompat-v7:22.2.1'
}
android {
compileSdkVersion 22
buildToolsVersion '23.0.1'
lintOptions {
abortOnError false
}
}
android.libraryVariants.all { variant ->
LibraryPlugin plugin = project.plugins.getPlugin(LibraryPlugin)
JavaCompile javaCompile = variant.javaCompile
javaCompile.doLast {
String[] args = ["-showWeaveInfo",
"-1.5",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", plugin.project.android.bootClasspath.join(
File.pathSeparator)]
MessageHandler handler = new MessageHandler(true);
new Main().run(args, handler)
def log = 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
break;
case IMessage.WARNING:
case IMessage.INFO:
log.info message.message, message.thrown
break;
case IMessage.DEBUG:
log.debug message.message, message.thrown
break;
}
}
}
}
查看實例:http://pan.baidu.com/s/1ge98AUR