在偶然的一次技术交流中,有大牛聊到了AOP的使用,当时不明所以,可能和当时的视野见识有关把,毕竟之前很多项目中都没有使用到AOP。所以趁今天比较闲,来彻底 弄明白AOP编程的相关技术实现。
AOP含义
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP实现方式
AspectJ: 一个 JavaTM 语言的面向切面编程的无缝扩展(适用Android)。
Javassist for Android: 用于字节码操作的知名 java 类库 Javassist 的 Android 平台移植版。
DexMaker: Dalvik 虚拟机上,在编译期或者运行时生成代码的 Java API。
ASMDEX: 一个类似 ASM 的字节码操作库,运行在Android平台,操作Dex字节码
AOP术语理解
<1>通知,增强处理:Advice, 需要实现切面的功能点,比如登录验证,打印日志,耗时计算分析,主要是实现干什么,什么时候干(before,after,around等注解实现)
<2>连接点:JoinPoint, 允许执行通知,或者增强处理调用的地方,基本每个方法的前后都是,或者异常抛出时
<3>切入点:Pointcut, 根据符合要求的连接点,使用注解进行切入的地方,比如一个类中某些方法作为一个切入点,执行该方法前干什么,执行后干什么,异常抛出时干什么,以一个或多个方法作为切入点,切入点指明在哪干
<4>切面:Aspect, 切面是通知和切入点的结合
<5>目标:需要嵌入切入点的被执行对象,具体指某个类的方法,属性,或者构造器
<6>织入:Weaving, 把切面应用到目标对象来创建新的代理对象的过程
AOP语法与注解
下面讲述的AOP语法与注解的使用,都是基于AspectJ这个框架来说。
1.AOP注解与使用
@Aspect:声明切面,标记类
@Pointcut(切点表达式):定义切点,标记方法
@Before(切点表达式):前置通知,切点之前执行
@Around(切点表达式):环绕通知,切点前后执行
@After(切点表达式):后置通知,切点之后执行
@AfterReturning(切点表达式):返回通知,切点方法返回结果之后执行
@AfterThrowing(切点表达式):异常通知,切点抛出异常时执行
2.AOP切点表达式
AOP切点表达式主要是用于切点中,用作切点的筛选条件表达式。AOP切点表达式有call,execution,get,set,pre-initialition,initialition,static initialition,hander等,常用的是call,execution,get,set, handler等,下面的图片更具有说服力:
3.AOP切点表达式语法
对于AOP切点表达式的理解,下面的图片描述的很详细了,理解起来还是比较容易的,上手也快。
4.AOP复用切点表达式
注解@Pointcut是专门用来定义切点的,让切点表达式可以复用
比如:你可能需要在切点执行之前和切点报出异常时做些动作(如:出错时记录日志)
@Before("execution(* com.lqr..*(..))")public void before(JoinPoint point) {
System.out.println("CSDN_LQR");
}@AfterThrowing(value = "execution(* com.lqr..*(..))", throwing = "ex")public void afterThrowing(Throwable ex) {
System.out.println("记录日志");
}
复用实现:定义一个空方法,使用@Pointcut注解
@Pointcut("execution(* com.lqr..*(..))")public void pointcut() {}
这时"pointcut()"就等价于"execution(* com.lqr..*(..))",那么上面的代码就可以这么改了:
@Before("pointcut()")public void before(JoinPoint point) {
System.out.println("CSDN_LQR");
}@AfterThrowing(value = "pointcut()", throwing = "ex")public void afterThrowing(Throwable ex) {
System.out.println("记录日志");
}
5.AOP切点表达式中加入注解
完整的切点表达式,其实还具备注解选项,完整的表达式如下:
execution(<@注解类型模式>? <修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)
实现步骤一般如下:
1.自定义注解类
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)public @interface TestAnnoTrace {
String value();
int type();
}
2.使用自定义注解标记切点
将自定义注解运用到具体方法中,使用方式和普通的注解一样
@TestAnnoTrace(value = "lqr_test", type = 1)public void test(View view) {
System.out.println("Hello, I am CSDN_LQR");
}
3.修改原来切点表达式
@Pointcut("execution(@com.lqr.androidaopdemo.TestAnnoTrace * *(..))")public void myPointcut() {}
4.获取切点注解属性值
使用JoinPoint对象获取切点注解属性值,如下所示:
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();// 通过Method对象得到切点上的注解
TestAnnoTrace annotation = method.getAnnotation(TestAnnoTrace.class);String value = annotation.value();int type = annotation.type();
写在最后
以上例子参考的链接为:https://www.cnblogs.com/weizhxa/p/8567942.html
在此致谢作者“CSDN_LQR”
写的不好,还望高人多多指点!
网友评论