一直觉得对AOP了解得比较清楚了,不就是面向切面编程嘛,应用最多的地方,就是日志打印,没什么难点。可是有一天一个朋友微信发了一张图,问了两个问题:
1、Spring AOP的设计原理是什么?
2、在Spring AOP中关注点(concern)和横切关注点(cross-cutting concern)有什么不同?
我发现完全蒙圈,根本答不上来啊,真是汗颜,趁有空,赶紧抽时间整理下。
如果不用AOP,我们平时打印日志是这样的:
public class AOPTest {
public boolean A(String a) {
if (a.equals("a")) {
return true;
} else {
return false;
}
}
public boolean B(String b) {
if (b.equals("a")) {
return true;
} else {
return false;
}
}
public boolean C(String c) {
if (c.equals("a")) {
return true;
} else {
return false;
}
}
public static void main(String[] args) {
AOPTest te = new AOPTest();
if (te.A("a")) {
System.out.println("我是A方法");
} else {
System.out.println("我不是A方法");
}
if (te.B("b")) {
System.out.println("我是B方法");
} else {
System.out.println("我不是B方法");
}
if (te.C("C")) {
System.out.println("我是C方法");
} else {
System.out.println("我不是C方法");
}
}
}
你会发现,打印个日志简直要人命,到处System.out,如果使用AOP,代码就会简洁很多,比如:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
public class AOPTest {
@Around("bean(*Service)") // 指定要监控的bean中的方法
public Object testObject(ProceedingJoinPoint jp) throws Throwable { // 参数的意思是代理执行原软件中的方法
System.out.println(jp.getSignature() + "开始执行"); // 在方法执行之前执行
Object val = jp.proceed();
System.out.println(jp.getSignature() + "执行成功");// 在方法执行之后执行
return val;
}
}
我们都知道,软件开发分为持久层、业务层和控制层,通过切面编程,现在所有业务层的方法执行前后都会打出日志,所以:
1、什么是Spring AOP?
在面向对象编程中,关键的单元是对象,但AOP的关键单元是切面(关注点),像日志或者事务这些分散的切面(横切关注点——可以影响到整个应用的关注点)应该被尽量地集中到一个地方以方便管理(事务管理、权限、日志、安全)。而AOP就是作用于这些横切关注点,使得代码在当下和将来都变得容易维护,一般AOP通过如下方式进行使用:
使用AspectJ 注解风格
使用Spring XML 配置风格
2、简述一下Spring AOP的设计原理
主要的分代理的创建和代理的调用两部分,比如UML图:
1)代理的创建
创建代理工厂:拦截器数组,目标对象接口数组,目标对象。
创建代理工厂时,默认会在拦截器数组尾部再增加一个默认拦截器 —— 用于最终的调用目标方法。
当调用 getProxy 方法的时候,会根据接口数量大余 0 条件返回一个代理对象(JDK or Cglib)。
注意:创建代理对象时,同时会创建一个外层拦截器,这个拦截器就是 Spring 内核的拦截器,用于控制整个 AOP 的流程。
2)代理的调用
当对代理对象进行调用时,就会触发外层拦截器。
外层拦截器根据代理配置信息,创建内层拦截器链。创建的过程中,会根据表达式判断当前拦截是否匹配这个拦截器。而这个拦截器链设计模式就是职责链模式。
当整个链条执行到最后时,就会触发创建代理时那个尾部的默认拦截器,从而调用目标方法,最后返回。
3、AOP有哪些可用的实现?
基于Java的主要AOP实现有:
AspectJ
Spring AOP
JBoss AOP
4、Spring中有哪些通知类型(advice)?
Before(前置通知): 连接点之前执行,除非抛异常,否则没有能力中断执行流(@Before 注解)
After(后置通知): 无论连接点是通过什么方式退出的(正常返回或者抛出异常)都会在结束后执行这些Advice(@After 注解)
After Retuning(返回通知): 在连接点正常结束之后(没有抛出异常正常返回)执行的Advice(@AfterReturning 注解)
After Throwing(异常通知): 如果方法通过抛出异常来退出的话,这个Advice就会被执行(@AfterThrowing 注解)
Around(环绕通知):
5、在Spring AOP中关注点和横切关注点有什么不同?
关注点:我们在应用的模块中实现以解决特定业务问题的方法。比如库存管理、航运管理、用户管理等。
横切关注点:贯穿整个应用程序的关注点。像事务管理、权限、日志、安全等。
6、Spring AOP的代理是什么?
Spring AOP是基于代理实现的,默认为标准的 JDK 动态代理。这使得任何接口(或者接口的集合)可以被代理。
Spring AOP 也使用 CGLIB 代理。如果业务对象没有实现任何接口那么默认使用CGLIB。