之前就Spring AOP的基本术语和原理及使用有了一定的认识,作为Spring核心特性之一,AOP同样很有必要重点掌握。这次沉淀将会开启AOP源码阅读的序幕。
对于源码的理解,以注释添加在对应代码块上方
一、AOP概念回顾
为什么会有面向切面编程(AOP)?众所周知,Java是一个面向对象(OOP)的语言,但它有一些弊端,例如:当我们需要为多个不具有继承关系的对象引入一个公共行为,例如日志、权限、事务、性能监测等功能时,只能在在每个对象里引用公共行为,这样做不便于维护,而且有大量重复代码,通常我们更希望的是这些模块可以实现热插拔特性而且无需把外围的代码入侵到核心模块中。
为了能够更好地将系统级别的代码抽离出来,去掉与对象的耦合,就产生了面向AOP(面向切面)。
如上图所示,OOP属于一种横向扩展,AOP是一种纵向扩展。AOP依托于OOP,进一步将系统级别的代码抽象出来,进行纵向排列,实现低耦合。
AOP的出现弥补了OOP的这点不足。假设现在我们把日志、权限、事务、性能监测等外围业务看作单独的关注点(也可以理解为单独的模块),每个关注点都可以在需要它们的时刻及时被运用而且无需提前整合到核心模块中。
二、源码剖析
1. Demo
public static void main(String[] args) {
//创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
//设置目标对象
proxyFactory.setTarget(new MyLogServiceImpl());
//前置增强
proxyFactory.addAdvice(new MyLogBefore());
//后置增强
proxyFactory.addAdvice(new MyLogAfter());
//从代理工厂中获取代理
MyLogService myLogService = (MyLogService) proxyFactory.getProxy();
myLogService.log("x");
}
2. 源码剖析
在demo中,直接获取的是一个代理,不是要使用的实现类,这是因为AOP其实就是代理模式,在编译期或者运行期,给我们原来的代码增加一些功能,成为一个代理。当我们调用的时候,实际就是调用的代理类。
代码中首先创建一个代理工厂实例:
ProxyFactory proxyFactory = new ProxyFactory();
代理工厂的作用就是使用编程的方式创建AOP代理。ProxyFactory继承自AdvisedSupport,AdvicedSupport是AOP代理的配置管理器。
需要明白的是,Spring中实现AOP,就是生成一个代理,然后在使用的时候调用代理。
首先从方法proxyFactory.setTarget(new LoginServiceImpl())开始剖析源码:
public void setTarget(Object target) {
/**首先根据给定的目标实现类,创建一个单例的TargetSource
**然后设置TargetSource
*/
setTargetSource(new SingletonTargetSource(target));
}
类SingletonTargetSource实现接口TargetSource :
public interface TargetSource {
//返回目标类的类型
Class getTargetClass();
/**查看TargetSource是否是static的
*静态的TargetSource每次都返回同一个Target
*/
boolean isStatic();
//获取目标类的实例
Object getTarget() throws Exception;
//释放目标类
void releaseTarget(Object target) throws Exception;
}
类SingletonTargetSource定义如下:
public final class SingletonTargetSource implements TargetSource, Serializable {
//用来保存目标类
private final Object target;
//构造方法
public SingletonTargetSource(Object target) {
this.target = target;
}
//直接返回目标类的类型
public Class getTargetClass() {
return target.getClass();
}
//返回目标类
public Object getTarget() {
return this.target;
}
//释放目标类,代码逻辑为空
public void releaseTarget(Object o) {
// Nothing to do
}
//是否为静态,这里直接返回true
public boolean isStatic() {
return true;
}
//重写equals方法
public boolean equals(Object other) {
//相等,返回true
if (this == other) {
return true;
}
//如果不是SingletonTargetSource类型的返回false
if (!(other instanceof SingletonTargetSource)) {
return false;
}
SingletonTargetSource otherTargetSource = (SingletonTargetSource) other;
//判断目标类是否相等
return ObjectUtils.nullSafeEquals(this.target, otherTargetSource.target);
}
//重写toString方法
public String toString() {
return "SingletonTargetSource: target=(" + target + ")";
}
}
在AdvisedSupport类中的设置目标类setTargetSource方法:
public void setTargetSource(TargetSource targetSource) {
if (isActive() && getOptimize()) {
throw new AopConfigException("Can't change target with an optimized CGLIB proxy: it has its own target");
}
//将构建的TargetSource缓存起来
this.targetSource = targetSource;
}
设置了要代理的目标类之后,接下来就是添加通知,即添加增强类,proxyFactory.addAdvice()方法是添加增强类的方法。对应demo中是:
//前置增强
proxyFactory.addAdvice(new MyLogBefore());
//后置增强
proxyFactory.addAdvice(new MyLogAfter());
addAdvice方法的参数是一个Advice类型的类,也就是通知或者叫增强,这里先介绍有关通知Advice的代码。
Advice接口
Advice不属于Spring,是AOP联盟定义的接口。Advice接口并没有定义任何方法,是一个空的接口,用来做标记,实现了此接口的的类是一个通知类。Advice有几个子接口:
- BeforeAdvice,前置增强,即在我们的目标类之前调用的增强,未定义任何方法;
- AfterReturningAdvice,方法正常返回前的增强,该增强可以看到方法的返回值,但不能更改返回值;
- ThrowsAdvice,抛出异常时候的增强,是一个标志接口,未定义任何方法;
- Interceptor,拦截器,未定义任何方法,表示一个通用的拦截器。不属于Spring;
- DynamicIntroductionAdvice,动态引介增强,有一个方法implementsInterface。
MethodBeforeAdvice接口,是BeforeAdvice的子接口,表示在方法前调用的增强。
public interface MethodBeforeAdvice extends BeforeAdvice {
/**在给定的方法调用前,调用该方法
*参数method是被代理的方法
*参数args是被代理方法的参数
*参数target是方法调用的目标,可能为null
*/
void before(Method m, Object[] args, Object target) throws Throwable;
}
我们来看看向代理工厂中添加增强的addAdvice方法,addAdvice方法在AdvisedSupport类中:
public void addAdvice(Advice advice) throws AopConfigException {
/**advisors是Advice列表,是一个LinkedList
*如果被添加进来的是一个Interceptor,会先被包装成一个Advice
*添加之前现获取advisor的大小,当做添加的Advice的位置
*/
int pos = (this.advisors != null) ? this.advisors.size() : 0;
//添加Advice
addAdvice(pos, advice);
}
未完跟进中......(addAdvice(pos, advice)方法)
方法addAdvice(pos, advice)源码:
//添加Advice
public void addAdvice(int pos, Advice advice) throws AopConfigException {
//只能处理已经实现了AOP联盟的接口的拦截器
if (advice instanceof Interceptor && !(advice instanceof MethodInterceptor)) {
throw new AopConfigException(getClass().getName() + " only handles AOP Alliance MethodInterceptors");
}
/**如果advice是IntroductionInfo接口类型,
*不需要IntroductionAdvisor
*/
if (advice instanceof IntroductionInfo) {
addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
}
/**如果advice是动态引介增强,
*需要IntroductionAdvisor
*/
else if (advice instanceof DynamicIntroductionAdvice) {
throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
}
else {
//添加增强器,需要先将增强包装成增强器,然后进行添加
addAdvisor(pos, new DefaultPointcutAdvisor(advice));
}
}
添加增强的过程:实际调用添加增强器这个方法
- 将Advice包装成一个PointCutAdvisor;
- 然后在添加增强器。
Advisor接口
Advisor,增强器,它持有一个增强Advice和一个过滤器,用来决定Advice的所使用的位置。
public interface Advisor {
//判断Advice是否存在于每个实例中
boolean isPerInstance();
//返回当下持有的Advice
Advice getAdvice();
}
PointcutAdvisor
PointcutAdvisor是一个持有Pointcut切点的增强器,拥有一个Advice和一个Pointcut。
public interface PointcutAdvisor extends Advisor {
//获取Pointcut
Pointcut
}
Pointcut接口
即切入点,定义了哪些连接点需要被织入横切逻辑。
public interface Pointcut {
//类过滤器,用于明确需要拦截的类
ClassFilter getClassFilter();
//方法匹配器,用于明确需要拦截的方法
MethodMatcher getMethodMatcher();
Pointcut TRUE = TruePointcut.INSTANCE;
}
ClassFilter接口
public interface ClassFilter {
//判断所给的类是否需要拦截
boolean matches(Class clazz);
ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
MethodMatcher接口
public interface MethodMatcher {
//静态方法匹配
boolean matches(Method m, Class targetClass);
//是否是运行时动态匹配
boolean isRuntime();
//运行时动态匹配
boolean matches(Method m, Class targetClass, Object[] args);
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
了解了这些相关定义之后,回到源码逻辑的剖析,让我们来看看添加增强器方法addAdvisor的具体实现:
public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
//如果增强器是引介增强器
if (advisor instanceof IntroductionAdvisor) {
addAdvisor(pos, (IntroductionAdvisor) advisor);
}
else {
//其他的增强器处理
addAdvisorInternal(pos, advisor);
}
}
方法 addAdvisorInternal(pos, advisor)的源码:
private void addAdvisorInternal(int pos, Advisor advice) throws AopConfigException {
if (isFrozen()) {
throw new AopConfigException("Cannot add advisor: config is frozen");
}
//把Advice添加到LinkedList中指定位置pos
this.advisors.add(pos, advice);
//同时更新Advisors数组
updateAdvisorArray();
//通知监听器
adviceChanged();
}
获取代理
上述源码是在组装代理工厂,接下类我们继而剖析代理的生成,方法proxyFactory.getProxy()这一步就是获取代理的过程:
public Object getProxy() {
//创建AOP代理
AopProxy proxy = createAopProxy();
//返回代理
return proxy.getProxy();
}
Spring中,创建代理通常有两种方式:
- JDK动态代理;
- CGLIB动态代理。
而这里的创建AOP代理就是生成这两种代理中的一种。
protected synchronized AopProxy createAopProxy() {
if (!this.isActive) {
activate();
}
//获取AOP代理工厂,然后创建代理
return getAopProxyFactory().createAopProxy(this);
}
public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
//判断使用ObjenesisCglibAopProxy还是JdkDynamicAopProxy
/**如果代理的是类,
*就使用CGLIB的方式来创建代理
*/
boolean useCglib = advisedSupport.getOptimize() || advisedSupport.getProxyTargetClass() || advisedSupport.getProxiedInterfaces().length == 0;
if (useCglib) {
return CglibProxyFactory.createCglibProxy(advisedSupport);
}
else {
/**如果代理的是接口,
*就使用JDK动态代理来创建代理
*/
return new JdkDynamicAopProxy(advisedSupport);
}
}
JDK动态代理
看下JDK动态代理的方式,对于方法的调用,调用的是代理类的invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation = null;
Object oldProxy = null;
boolean setProxyContext = false;
//所代理的目标对象
TargetSource targetSource = advisedSupport.targetSource;
Class targetClass = null;
Object target = null;
try {
//equal、hashCode 等方法
if (method.getDeclaringClass() == Object.class && "equals".equals(method.getName())) {
return equals(args[0]) ? Boolean.TRUE : Boolean.FALSE;
}
else if (Advised.class == method.getDeclaringClass()) {
return AopProxyUtils.invokeJoinpointUsingReflection(this.advisedSupport, method, args);
}
Object retVal = null;
//代理目标对象
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
if (this.advisedSupport.exposeProxy) {
// Make invocation available if necessary
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
//获取此方法的拦截链
List chain = this.advisedSupport.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this.advisedSupport, proxy, method, targetClass);
//如果没有配置通知
if (chain.isEmpty()) {
//直接调用目标对象的方法
retVal = AopProxyUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
//如果配置了通知,创建一个方法调用
invocation = new ReflectiveMethodInvocation(proxy, target,
method, args, targetClass, chain);
//执行通知链,沿着通知器链调用所有的通知
retVal = invocation.proceed();
}
if (retVal != null && retVal == target) {
//返回值为自己
retVal = proxy;
}
//返回
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
上述方法步骤:
- 如果拦截链不为空,则创建一个ReflectiveMethodInvocation;
- 调用其proceed方法;3
- proceed方法的调用会递归调用,直到所有的MethodInterceptor调用完
- 如果拦截链为空,直接调用目标对象的方法。