Coder Social home page Coder Social logo

aspectjdemo's Introduction

android中AOP编程的应用

1、AOP的概念:

面向侧面的程序设计(aspect-oriented programming,AOP,又译作面向方面的程序设计、观点导向编程、剖面导向程序设计)是计算机科学中的一个术语,指一种程序设计范型。该范型以一种称为侧面(aspect,又译作方面)的语言构造为基础,侧面是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点(crosscutting concern)。侧面的概念源于对面向对象的程序设计的改进,但并不只限于此,它还可以用来改进传统的函数。与侧面相关的编程概念还包括元对象协议、主题(subject)、混入(mixin)和委托。(摘自维基百科

2、AOP在Android中的应用点:

aop是一种面向切面的编程**,目的在于从切面插入自己需要的代码,在不破坏、不耦合原有代码逻辑的基础上,实现相关的功能,在Android中的应用场景非常丰富,如:数据统计、日志记录、用户行为统计、应用性能统计、数据校验、行为拦截,等等应用场景。

3、在Android中,如何实现AOP编程:

aop编程的实现技术方案有很以下几种:

  • APT(直接插入java文件);
  • Aspectj(编织class文件);
  • javassist(修改class文件);

这里主要介绍Aspectj:

4、Aspectj框架入门介绍:

环境搭建:

aspectj的环境搭建步骤比较复杂,这里参考了Hujiang的项目,对gradle插件进行了修改封装;
使用步骤:

在项目的build.gradle文件中加入如下代码:

repositories {
    ...
    maven { url 'https://jitpack.io' }
}
dependencies {
    ...
 classpath 'com.github.alfredxl:android-aspectj:0.9.0'
}

在application模块中的build.gradle文件中加入:

apply plugin: 'android-aspectjx'

aspectj介绍

aspectj术语

名称 描述
JPoint 代码可注入的点,比如一个方法的调用处或者方法内部、“读、写”变量等。
Pointcut 用来描述 JPoint 注入点的一段表达式,比如:调用 Animal 类 fly 方法的地方,call(* Animal.fly(..))。
Advice 常见的有 Before、After、Around 等,表示代码执行前、执行后、替换目标代码,也就是在 Pointcut 何处注入代码。
Aspect Pointcut 和 Advice 合在一起称作 Aspect。

JPoint语法:

符号 描述
* 表示任何数量的字符,除了(.)
.. 表示任何数量的字符包括任何数量的(.)
+ 描述指定类型的任何子类或者子接口
! 一 元操作符:
||、&& 二 元操作符

主要例子:

例子 解析
*Account 使用Account名称结束的类型,如SavingsAccount和CheckingAccount
java.*.Date 类型Date在任何直接的java子包中,如java.util.Date和java.sql.Date
java..* 任何在java包或者所有子包中的类型,如java.awt和java.util或者java.awt.event 和java.util.logging
javax..*Model+ 所有javax包或者子包中以Model结尾的类型和其所有子类,如TableModel,TreeModel。
!vector 所有除了Vector的类型
Vector || Hashtable Vector或者Hashtable类型
java.util.RandomAccess+ RandomAccess的所有子类
void Account.set*(*) Account中以set开头,并且只有一个参数类型,无返回值的方法
void Account.*() Account中所有的没有参数的void 方法
public * Account.*() Account中所有没有参数的public 方法
public * Account.*(..) Account中所有的public 方法
* Account.*(..) Account中的所有方法,包括private方法
!public * Account.*(..) 所有的非public 方法
* Account+.*(..) 所有的方法,包括子类的方法
* java.io.Reader.read(..) 所有的read方法
* java.io.Reader.read(char[],..) 所有以read(char[])开始的方法,包括read(char[])和read(char[],int,int)
* javax..*.add*Listener(EventListener+) 命名以add开始,以Listener结尾的方法,参数中为EventListener或子类
* *.*(..) throws RemoteException 抛出RemoteException的所有方法

Pattern规则

名称 描述
MethodPattern : [!] [@Annotation] [public,protected,private] [static] [final] 返回值类型 [类名.]方法名(参数类型列表) [throws 异常类型]
ConstructorPattern: [!] [@Annotation] [public,protected,private] [final] [类名.]new(参数类型列表) [throws 异常类型]
FieldPattern: [!] [@Annotation] [public,protected,private] [static] [final] 属性类型 [类名.]属性名
TypePattern: 其他 Pattern 涉及到的类型规则也是一样,可以使用 '!'、''、'..'、'+','!' 表示取反,'' 匹配除 . 外的所有字符串,'*' 单独使用事表示匹配任意类型,'..' 匹配任意字符串,'..' 单独使用时表示匹配任意长度任意类型,'+' 匹配其自身及子类,还有一个 '...'表示不定个数

Pointcut语法:

语法 描述
execution(MethodPattern) 方法执行
call(MethodPattern) 方法调用
execution(ConstructorPattern) 构造函数执行
call(ConstructorPattern) 构造函数被调用
staticinitialization(TypePattern) static 块初始化
get(FieldPattern) 属性读操作
set(FieldPattern) 属性写操作
handler(TypePattern) 异常处理
adviceexecution() 所有 Advice 执行

间接选择Pointcut语法:

语法 描述
within(TypePattern): TypePattern表示某个包或者类中包含的JPoint,可以使用通配符;
withincode(ConstructorPattern MetodPattern):
cflow(pointcuts): 比如cflow(call Animal.fly): 标识调用Animal.fly函数时所包含的JPoint,包含fly的call这个JPoint本身;
cflowbelow(pointcuts): 比如cflowbelow(call Animal.fly): 标识调用Animal.fly函数时所包含的JPoint,但不包含fly的call这个JPoint本身;
this(Type): JPoint所在的对象是否满足instanceof Type条件(注:不能使用通配符,与within类似,但within包含内部类, 而this不包含);
target(Type): 与this相对,表示Pointcut所在对象是否满足instanceof Type条件(注:不能使用通配符);
args(TypeSignature): Constructor Signature|Method Signature的参数类型,比如args(int,..)表示第一个参数是int, 后面的参数个数和类型不限;
if(BooleanExpression): 满足表达式的 Join Point,表达式只能使用静态属性、Pointcuts 或 Advice 暴露的参数、thisJoinPoint 对象。

Advice语法:

语法 描述
Before(Pointcut): 在执行JPoint之前;
After(Pointcut): 在执行JPonit之后;
Aroud(Pointcut): 替换原需要执行的代码,如需执行原代码,需调用joinPoint.proceed()方法,不可与Before和After同时使用;
AfterReturning(Pointcut): JPoint 为方法调用且正常 return 时,不指定返回类型时匹配所有类型;
AfterThrowing(Pointcut): JPoint 为方法调用且抛出异常时,不指定异常类型时匹配所有类型;

aspectj示例:

execution(MethodPattern)(JPoint方法执行)

@Aspect
public class OtherJpoint {

@Before("execution(* android.view.View.OnClickListener.onClick(android.view.View))")
public void onViewClickListener(JoinPoin joinPoint) throws Throwable {
if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            Object object = joinPoint.getArgs()[0];
 if (object instanceof TextView) {
                Log.d("aopLog", "clickViewName: " + ((TextView) object).getText().toString());
 }
        }
 }
}

该切入点执行的效果为:在所有实现View的点击事件的onClick方法内部代码执行之前打印View的信息

execution(ConstructorPattern)(JPoint构造器执行)

@Before("execution(com.aspectj.demo.bean.Person.new(..))")
public void onStartPageConstructor(JoinPoint joinPoint) throws Throwable {
    Log.d("aopLog", "this:" + joinPoint.getThis().toString());
}

该切入点执行的效果为:在所有创建Person对象的时候,执行Person对象构造函数之前打印该对象的信息; 注意: 构造函数执行, 没有返回值类型, 且函数名只能是new

call(MethodPattern) (JPoint方法调用)

@Before("call(* com.aspectj.demo.StartPage.setButtonOneData(..))")
public void onCallStartPagesetButtonOneData(JoinPoint joinPoint) throws Throwable {
if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
        Object object = joinPoint.getArgs()[0];
 Log.d("aopLog", "button_text: " + object.toString());
 }
}

该切入点的效果为:在所有调用com.aspectj.demo.StartPage.setButtonOneData(..)该方法的代码之前打印传递给该方法的型参

staticinitialization(TypePattern) (JPoint类初始化)

@Before("staticinitialization(com.aspectj.demo.bean.Person)")
public void onStartPageStaticinitialization(JoinPoint joinPoint) throws Throwable {
    Log.d("aopLog", "staticinitialization_this:" + joinPoint.getStaticPart().toString());
}

该切入点的效果为:在Person初始化之前打印信息

get(FieldPattern) (JPoint属性读操作)

@Before("get(* com.aspectj.demo.bean.Person.*)")
public void getPersonField(JoinPoint joinPoint) throws Throwable {
    Log.d("aopLog", "getPersonField:" + joinPoint.getStaticPart().toString());
}

该切入点的效果为,在所有获取Person对象属性的代码之前插入打印信息

set(FieldPattern) (JPoint属性写操作)

@Before("set(* com.aspectj.demo.bean.Person.*)")
public void setPersonField(JoinPoint joinPoint) throws Throwable {
    Log.d("aopLog", "setPersonField:" + joinPoint.getStaticPart().toString());
}

该切入点的效果为,在所有设置Person对象属性值的代码之前插入打印信息

handler(TypePattern) (JPoint例外处理执行)

private fun showToast(message: String) {
if (message.isNotEmpty()) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }
try {
throw IllegalArgumentException()
    } catch (e: IllegalArgumentException) {

    }
}
@Before("handler(java.lang.IllegalArgumentException)")
public void handlerIllegalArgumentException(JoinPoint joinPoint) throws Throwable {
    Log.d("aopLog", "handlerIllegalArgumentException:" + joinPoint.getStaticPart().toString());
}

该切入点的效果为,在所有编译时匹配的IllegalArgumentException异常,将在异常抛出前,打印信息; 注意: handler只支持Before,而且只能匹配编译期异常捕获,并且不能捕获该异常的子类。

within(TypePattern)

@Pointcut("within(com.aspectj.demo.StartPage)")
public void withinStartPage() {
}

@Pointcut("call(* android.widget.Toast.show(..))")
public void showToast() {
}

@Before("withinStartPage() && showToast()")
public void withinStartPageAndShowToast(JoinPoint joinPoint) throws Throwable {
    Log.d("aopLog", "withinStartPageAndShowToast:" + joinPoint.getStaticPart().toString());
}

该切入点的效果为,在StartPage类中调用Toast方法之前打印相关信息

withincode(MethodPattern)

@Pointcut("withincode(* com.aspectj.demo.StartPage.showToast(..))")
public void inStartPageShowToast() {
}
@Pointcut("call(* android.widget.Toast.show(..))")
public void showToast() {
}
@Before("inStartPageShowToast() && showToast()")
public void inStartPageShowToastAndShowToast(JoinPoint joinPoint) throws Throwable {
    Log.d("aopLog", "inStartPageShowToastAndShowToast: " + joinPoint.getSignature().getName());
}

该切入点的效果为:在com.aspectj.demo.StartPage.showToast()方法中调用了Toast方法之前打印相关信息

注解

@Retention(RetentionPolicy.CLASS)
@Target({ElementType.METHOD})
public @interface ActivityOnCreate {
}
@Pointcut("execution(@com.aspectj.aspectjaplay.activitylife.ActivityOnCreate * *(..))")
public void ActivityOnCreate() {
}

@Around("ActivityOnCreate()")
public void ActivityOnCreate(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
 joinPoint.proceed();
 long endTime = System.currentTimeMillis();
 String key = joinPoint.getSignature().getName();
 Log.d("aopLog", "execution_onActivityMethodAround: " + joinPoint.getThis().getClass().getSimpleName() + "_" 
 + key + ":" + (endTime - startTime));
}

该切入点的效果为,在使用了ActivityOnCreate 注解的目标方法执行前进行拦截并实行相关操作

这里关于Around的切入方式需要特殊说明一下,由于Around是切入整个方法的执行体,把整个方法执行体作为一个返回参数,所以在切有返回值的方法时,必须如下定义

@Around("Test()")
public Object Test(ProceedingJoinPoint joinPoint) throws Throwable {
Object object = joinPoint.proceed();
return object ;
}

即切入点方法撰写的时候必须是返回Object的方法,然后返回 joinPoint.proceed() 的值

总结:

本篇介绍,对AOP及Aspectj的介绍仅仅只涉及到到入门知识,更深入的学习,欢迎大家一起加入@QQ32038305。

aspectjdemo's People

Contributors

765947965 avatar alfredxl avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.