Spring 有几个关键词, IoC 和 AOP 是 Top2, 由此可见 AOP 在 Spring 框架中的作用, Spring 事务管理就是用 AOP 实现
说 AOP 之前应该先提下 OOP, OOP (Object-Oriented Programming) 是面向对象编程, 它使用归纳法把具有共性的东西归类并使之模块化, 达到便于维护可扩展的目的, 可以对业务需求进行很好的分解使其模块化
AOP (Aspect-Oriented Programming)与 OOP 在概念上属于同一范畴的, Aspect 对于 AOP 相当于 Class 之对于 OOP, 它是面向切面的编程, 它可以简化系统需求和实现时间的对比关系, 是对 OOP 的一种补足
所以 AOP 和 OOP 一样, 是一种理念, 而实现这种理念就需要有具体的产品, 也就是实现, 比如 AspectJ: Java 语言的 AOP 实现, AspectC: C 语言的 AOP 实现...
Spring AOP 也是 一种 Java 语言的 AOP 实现, 但 Spring AOP 不是将所有的 AOP 需求都囊括在内, 而是以有限的 20% 的 AOP 支持, 来满足 80% 的 AOP 需求
主要介绍 5 个, 分别是 Joint point, Pointcut, Advice, Aspect, 以及 Target
A point during the execution of a program, such as the execution of a method or the handling of an exception.
比如:方法调用、方法执行、字段设置/获取、异常处理执行、类初始化、甚至是 for 循环中的某个点
理论上, 程序执行过程中的任何时点都可以作为作为织入点, 而所有这些执行时点都是 Joint point
但 Spring AOP 目前仅支持方法执行 (method execution)
A predicate that matches join points.
描述某一类 Joint points, 比如定义了很多 Joint point, 对于 Spring AOP 来说就是匹配哪些方法的执行
描述方式:
Action taken at a particular join point. 即 Joinpoint 横且逻辑执行的时机
before advice
在 Jointpoint 指定位置之前执行, 对于 Spring AOP 来说, 就是在某个方法执行之前执行
after advice
在 Jointpoint 指定位置之后执行, 对于 Spring AOP 来说, 就是在某个方法执行之后执行
又可分为三种, 分别是
around advice
顾名思义, 是围绕这 Joinpoint 前后, 比如在方法执行前后都可以执行, 所以同时兼有 before advice 和 after advice 的功能
Spring AOP 的 around advice 实现是利用 AOP Alliance 下的拦截器(Interceptor), 需要实现MethodInterceptor 接口
introduction
暂略
A modularization of a concern that cuts across multiple classes.
是对系统中横且点逻辑进行模块化封装的 AOP 概念实体, 一般 Aspect 可以包含多个 Pointcut 以及相关 Advice 定义
对Spring AOP 底层来说, Aspect 的概念使用 Advisor 代替, 一个 Advisor 只有一个 Pointcut 和 相应的 Advice
Spring 2.0 后, 由于集成了 AspectJ, 可以使用 AspectJ 相关的概念实体, 但在底层实现上还是原来的 Spring AOP 自己的实现
Linking aspects with other application types or objects to create an advised object.
将 AOP 织入到系统中, 是 AOP 和 OOP 连接共同合作的桥梁, 织入的方式可以有多种, compile time (AspectJ compiler), load time, runtime
Spring AOP 是运行时动态织入
An object created by the AOP framework in order to implement the aspect contracts.
AOP 具体的织入实现使用代理实现的, Spring AOP 使用的代理有两种, 分别是 JDK 动态代理 和 CGLIB 代理
要织入横切逻辑的目标对象, 因为 Spring AOP 使用运行时代理实现, 所以这个对象始终是一个代理对象 (proxiedobject)
下面这个图描述了各个概念所处的场景
FooAspect.java
Action.java/FooAction.java
public class FooAction implements Action {
@Override
public void action(String type) {
System.out.println("action type: " + type);
}
}
使用 IoC 容器
target
执行结果如下:
beforeAdvice
action type: foo
afterReturningAdvice
Spring AOP 的实现归根到底是利用代理实现的, 有种设计模式叫代理模式, 对, 就是它
Spring AOP 使用的代理方式有两种, 一种是使用基于反射(reflection)机制的 JDK dynamic proxy, 另一种是使用基于动态字节码生成技术的 CGLIB库
JDK 动态代理只能针对接口代理, 对基于类的代理却无能为力, 在这种情况下, Spring AOP 使用 CGLIB 动态字节码生成进行类的代理
定义: 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用
在代理模式中, 通常涉及4中角色,
注意: 代理模式中, 无论如何代理, 无论添加多少层代理逻辑, 最终需要调用目标对象上的同一方法来执行最初所定义的方法逻辑
这个问题会导致 Spring AOP 的一个实现缺陷, 后面对讲到
注意:代理类 SubjectProxy 和 SubjectImpl 都实现了相同的接口 Isubject
当 Client 通过代理对象的 request() 方法请求服务的时候, SubjectProxy 将转发该请求给 SubjectImpl, 但 SubjectProxy 的作用不只局限于转发, 更多时候是对请求添加更多的访问限制或这做一些额外的动作, 而 Spring AOP 中的 Advice 就可以看作是这些额外的动作
用法很简单, 只需实现接口 InvocationHandler 就可以了
RequestInvocationHandler.java
public class RequestInvocationHandler implements InvocationHandler {
private Object target;
public RequestInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before request"); // before action
Object result = method.invoke(target, args);
System.out.println("after request"); // after action
return result;
}
}
使用
ISubject subject = (ISubject) Proxy.newProxyInstance(
TestAop.class.getClassLoader(),
new Class[] {ISubject.class},
new RequestInvocationHandler(new SubjectImpl())
);
subject.request();
ISubject requestable = (ISubject) Proxy.newProxyInstance(
TestAop.class.getClassLoader(),
new Class[] {ISubject.class},
new RequestInvocationHandler(new RequestableImpl())
);
requestable.request();
JDK 动态代理的详细信息可以参考 一书
如果目标对象实现了接口, 则 Spring AOP 默认用 JDK 动态代理, 如果目标对象没有实现任何接口, Spring AOP 会尝试使用 CGLIB 的开源动态字节码生成类库, 如果 classpath 中未引入此库, 则会报错
动态字节码生成技术扩展对象行为到原理是, 对目标对象进行继承扩展, 为其生成相应的子类, 而子类可以通过重写来扩展父类的行为
Requestable.class/RequestInvocationHandler.class
public class Requestable {
public void request() {
System.out.println("request...");
}
}
public class RequestInvocationHandler implements InvocationHandler {
private Object target;
public RequestInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before request");
Object result = method.invoke(target, args);
System.out.println("after request");
return result;
}
}
使用:
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Requestable.class);
enhancer.setCallback(new RequestCtrlCallback());
Requestable req = (Requestable) enhancer.create();
req.request();
实现 net.sf.cglib.proxy.MethodInterceptor
接口即可
CGLIB 可以在系统运行期间动态的为目标对象生成相应的扩展子类, 它唯一的限制是无法对 final 方法进行重写