上一篇通过简单的分析,我们大概清楚了整个AOP代码实现的大体流程。本篇我们将从代码入手,一点点分解AOP的实现代码。
1.使用AOP的代码
先看一段代码,看看如何使用AOP的。
public class CodeMain {
public static void main(String[] args) {
//默认代理所有方法
proxyAllMethods();
//定制代理
//proxyMethod();
}
/**
* 默认情况。代理所有方法
*/
private static void proxyAllMethods(){
//1.创建被代理对象
Tiger tiger = new Tiger();
//2.创建spring代理工厂对象 ProxyFactory
//proxyFactory 是 config + factory 的存在 持有 aop 操作 的 所有的生产资料
ProxyFactory proxyFactory = new ProxyFactory(tiger);
//3. 添加拦截器
proxyFactory.addAdvice(new MethodInterceptor01());
proxyFactory.addAdvice(new MethodInterceptor02());
//4.获取代理对象,分析如何获取的代理对象?
Animals proxy = (Animals) proxyFactory.getProxy();
proxy.eat("人");
System.out.println("===================================");
proxy.run();
}
/**
* 代理指定的方法
*/
private static void proxyMethod(){
//1.创建被代理对象
Tiger tiger = new Tiger();
//2.创建spring代理工厂对象 ProxyFactory
//proxyFactory 是 config + factory 的存在 持有 aop 操作 的 所有的生产资料
ProxyFactory proxyFactory = new ProxyFactory(tiger);
//3.添加方法拦截
MyPointCut pointCut = new MyPointCut();
proxyFactory.addAdvisor(new DefaultPointcutAdvisor(pointCut,new MethodInterceptor01()));
proxyFactory.addAdvisor(new DefaultPointcutAdvisor(pointCut,new MethodInterceptor02()));
//4.获取代理对象 分析如何获得代理对象
Animals proxy = (Animals) proxyFactory.getProxy();
proxy.eat("人肉");
System.out.println("===================================");
proxy.run();
}
/**
* 方法拦截器
*/
private static class MethodInterceptor01 implements MethodInterceptor {
@Nullable
@Override
public Object invoke(@NonNull MethodInvocation invocation) throws Throwable{
System.out.println("method interceptor begin!----1");
Object result = invocation.proceed();
System.out.println("method interceptor end!---4");
return result;
}
}
private static class MethodInterceptor02 implements MethodInterceptor {
@Nullable
@Override
public Object invoke(@NonNull MethodInvocation invocation) throws Throwable{
System.out.println("method interceptor begin!----2");
Object result = invocation.proceed();
System.out.println("method interceptor end!----3");
return result;
}
}
}
interface Animals{
void eat(String food);
void run();
}
class Tiger implements Animals{
@Override
public void eat(String food) {
System.out.println("老虎吃"+food);
}
@Override
public void run() {
System.out.println("跑的贼快!");
}
}
public class MyPointCut implements Pointcut {
@Override
public ClassFilter getClassFilter() {
return clazz -> true;
}
@Override
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return method.getName().equals("eat");
}
@Override
public boolean isRuntime() {
return false;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return false;
}
};
}
}
这是使用AOP的两种方式,默认是代理全部方法,另一个则是代理指定的方法。接下来,我们来对源码进行分析。
2.抓手
private static void proxyAllMethods(){
//1.创建被代理对象
Tiger tiger = new Tiger();
//2.创建spring代理工厂对象 ProxyFactory
//proxyFactory 是 config + factory 的存在 持有 aop 操作 的 所有的生产资料
ProxyFactory proxyFactory = new ProxyFactory(tiger);
//3. 添加拦截器
proxyFactory.addAdvice(new MethodInterceptor01());
proxyFactory.addAdvice(new MethodInterceptor02());
//4.获取代理对象,分析如何获取的代理对象?
Animals proxy = (Animals) proxyFactory.getProxy();
proxy.eat("人");
System.out.println("===================================");
proxy.run();
}
这里面首先首先是创建了一个代理工厂,然后给代理工厂添加拦截器,最后通过代理工厂来获取代理对象,最后通过代理对象执行目标方法。
接下来我们来看代理工厂。
3.代理工厂
public ProxyFactory(Object target) {
//将目标对象封装成为 SingletonTargetSource 保存到父类字段内
setTarget(target);
//获取目标对象class 的所有接口 ,保存到父类字段内
setInterfaces(ClassUtils.getAllInterfaces(target));
}
在**ProxyFactory**
的构造器内将目标对象和目标对象实现的接口封装到了父类的字段里面。
上图是**ProxyFactory**
的继承关系,可以先简单过一下,有一个印象。
4.添加切面
**proxyFactory.addAdvice(new MethodInterceptor01())**
�
这一行代码是往代理工厂添加拦截器/切面。
看一下添加的流程
@Override
public void addAdvice(Advice advice) throws AopConfigException {
int pos = this.advisors.size();
addAdvice(pos, advice);
}
首先是调用了**AdvisedSupport**
类的添加切面方法。
在添加切面的方法里获取了当前类的增强器个数。然后和切面一起传递到重载的方法里。
@Override
public void addAdvice(int pos, Advice advice) throws AopConfigException {
Assert.notNull(advice, "Advice must not be null");
//不考虑,引介增强,很少用
if (advice instanceof IntroductionInfo) {
// We don't need an IntroductionAdvisor for this kind of introduction:
// It's fully self-describing.
addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
}
//不考虑,引介增强,很少用
else if (advice instanceof DynamicIntroductionAdvice) {
// We need an IntroductionAdvisor for this kind of introduction.
throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
}
else {
//spring中Advice对应的接口就是Advisor,Spring使用Advisor包装着AOP的Advice实例
addAdvisor(pos, new DefaultPointcutAdvisor(advice));
}
}
然后调用了**addAdvisor()**
,添加增强器。
因为我们没有指定切点,所以创建了一个默认的切点的增强器**DefaultPointcutAdvisor**
。
@Override
public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
//引介相关的逻辑,不考虑
if (advisor instanceof IntroductionAdvisor) {
validateIntroductionAdvisor((IntroductionAdvisor) advisor);
}
//委派模式
addAdvisorInternal(pos, advisor);
}
这里面调用了**addAdvisorInternal(pos, advisor)**
,继续往下看。
private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
Assert.notNull(advisor, "Advisor must not be null");
//如果当前AOP配置已经冻结了,不能在添加切面了,添加的话会抛出异常。
if (isFrozen()) {
throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
}
//如果传入的切面的位置大于当前切面的个数,抛异常,因为位置下标默认从-1开始。
if (pos > this.advisors.size()) {
throw new IllegalArgumentException(
"Illegal position " + pos + " in advisor list with size " + this.advisors.size());
}
//添加增强器
this.advisors.add(pos, advisor);
//清理缓存
adviceChanged();
}
这里进行一些校验逻辑,然后添加增强器,清理缓存。
5.获取代理对象
**proxyFactory.getProxy()**
�
/**
* 根据工厂的设置创建代理对象
* 可以反复的调用。
* 如果我们添加或者删除接口,效果会有所不同,可以添加和删除拦截器。
* 使用默认的类加载器:默认是线程上下文类加载器(如果需要创建代理)
*/
public Object getProxy() {
/**
* 创建AOP 的 代理 ,那么 AOP 的代理是什么 ?
*
* AopProxy
*
* createAopProxy() :去创建代理对象的逻辑
* getProxy():获取创建好的代理对象,这里有两个实现分别是jdk的动态代理和cglib的动态代理。
* CglibAopProxy
* JdkDynamicAopProxy
*
*/
return createAopProxy().getProxy();
}
这里面先是利用**createAopProxy()**
创建了一个代理对象,然后通过**getProxy()**
来获取一个代理对象。
我们先来分析**createAopProxy()**
,看一看代理对象是如何创建的?
/**
* 子类应该调用它来获得一个新的 AOP 代理。 他们不应该创建一个AOP代理this作为参数。
*/
protected final synchronized AopProxy createAopProxy() {
/**
* active属性实际上就是一个标记,在创建第一个代理对象的时候,会将他设置为true。
*/
if (!this.active) {
activate();
}
/**
* 分析一下下面这行代码的流程:
*
* 1. 获取aop的代理工厂 看一下AopProxyFactory
* 2. 使用工厂创建一个aop的代理 ,如何创建代理的?
*
*/
return getAopProxyFactory().createAopProxy(this);
}
先是通过**getAopProxyFactory()**
获取AOP的代理工厂,然后通过**createAopProxy(this)**
传入当前类来获取一个代理对象。
/**
* 这个类里面已经持有了一个默认的aop的代理工厂
* ctrl + h 查看当前类的继承关系
* 当前类是 ProxyFactory的父类,所以里面的代理工厂会被默认的初始化加载
* @return
*/
public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}
看一下上图类的继承关系,其实在创建**ProxyFactory**
的时候,隐式调用父类的构造器的时候,就已经在**ProxyCreatorSupport**
里面创建了一个默认的AOP代理工厂**DefaultAopProxyFactory**
。
接下来再来看如何创建一个AOP代理对象的。
/**
* @param config 就是我们的ProxyFactory对象,ProxyFactory他是一个配置管理对象
* 保存着创建代理对象所有的生产资料。
* @return 返回一个AOP的代理对象
* @throws AopConfigException 如果某些不期望我们修改的配置被修改,就会抛出异常
*/
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
/**
* 条件一:暂且不管
* 条件二:true 表示强制使用cglib代理,
* 条件三:true 表示被代理对象没有实现任何接口没有办法使用jdk的动态代理,只能使用cglib的动态代理
*/
if (!NativeDetector.inNativeImage() && //该条件不需要考虑
(
config.isOptimize() || //设置了这个属性,那么就是强制使用cglib的动态代理
config.isProxyTargetClass() || //设置了这个属性,那么就是强制使用cglib的动态代理
hasNoUserSuppliedProxyInterfaces(config) //判断被代理对象有没有实现接口,没有实现接口,那还用锤子jdk的动态代理
)
) {
//走到这里的话,很大程度上就已经会使用cglib的动态代理
//获取目标对象的类型,为空的话肯定没法继续往下走了,直接异常中断
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
}
//目标对象是一个接口 或者 已经是一个被代理过得类型(此时是多重代理) ,只能使用jdk的动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
//走cglib的动态代理
return new ObjenesisCglibAopProxy(config);
}
else {
//执行到这里的情况 : 实现了接口,大多数情况我们都是面向接口编程,走这里
return new JdkDynamicAopProxy(config);
}
}
根据条件判断我们到底是创建JDK的代理对象还是创建Cglib的代理对象,因为我们的案例代码的目标类是实现了接口的,所以默认会走jdk的动态代理。
6.JdkDynamicAopProxy
/**
* 使用给定的配置,通过构造器创建aop 的动jdk态代理对象
* 这里的config是啥?就是我们的代理工厂对象
*/
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
//非空断言
Assert.notNull(config, "AdvisedSupport must not be null");
//如果配置里面的切面数==0 && 配置里面的目标对象是空对象,那么代理无法继续往下走了,直接抛异常中断
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
//获取当前被代理对象实现的接口数组 ,具体的实现逻辑?
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
//查找所有被代理的接口,如果有equals 和 hashcode就打个标
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
}
判断如果配置里面没有该被代理对象的切面,或者被代理对象是空,那就不能往下走了,抛出异常。
获取当前被代理对象实现的接口数组**AopProxyUtils.completeProxiedInterfaces(this.advised, true)**
。
查找所有被代理的接口,如果有equals 和 hashcode就打个标。
看一下如何获取到当前被代理对象实现的接口数组的。
/**
* 拿到被代理对象的所有接口
*/
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
/*从proxyFactory中获取所有的target提取出来的接口*/
Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
/*如果接口长度是0*/
if (specifiedInterfaces.length == 0) {
//拿到目标对象的类型
Class<?> targetClass = advised.getTargetClass();
//如果目标对象的类型不为空
if (targetClass != null) {
//如果目标对象是一个接口,那么就将目标对象设置到接口列表里面
if (targetClass.isInterface()) {
advised.setInterfaces(targetClass);
}
//如果目标对象是一个代理类,那么也将目标对象设置到接口列表
else if (Proxy.isProxyClass(targetClass)) {
advised.setInterfaces(targetClass.getInterfaces());
}
specifiedInterfaces = advised.getProxiedInterfaces();
}
}
/*创建一个新的接口数组,长度是原接口数量+spring追加的三个接口数量*/
List<Class<?>> proxiedInterfaces = new ArrayList<>(specifiedInterfaces.length + 3);
for (Class<?> ifc : specifiedInterfaces) {
// 只有非密封接口实际上有资格进行JDK代理(在JDK 17上)
if (!ifc.isSealed()) {
proxiedInterfaces.add(ifc);
}
}
/*如果这个接口里面没有SpringProxy这个接口,那么就需要添加一个,打标,标识这个代理对象是Spring创建的*/
if (!advised.isInterfaceProxied(SpringProxy.class)) {
proxiedInterfaces.add(SpringProxy.class);
}
/*判断目标对象的所有接口是否有advice接口,没有就手动添加*/
if (!advised.isOpaque() && !advised.isInterfaceProxied(Advised.class)) {
proxiedInterfaces.add(Advised.class);
}
//如果目标对象的所有接口里面,没有DecoratingProxy的接口,那就添加一个
if (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class)) {
proxiedInterfaces.add(DecoratingProxy.class);
}
//返回接口类型数组
return ClassUtils.toClassArray(proxiedInterfaces);
}
接下来我们来看**getProxy(**
)的逻辑。
7.getProxy()
@Override
public Object getProxy() {
//这里如果没有传类加载器,就使用默认的类加载器,默认是线程上下文类加载器
return getProxy(ClassUtils.getDefaultClassLoader());
}
方法重载,继续往下走。
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
//打印日志的逻辑
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
//通过jdk的动态代理来创建代理对象 this == this::invoke 该方法最终会返回一个代理类对象
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
这里通过JDK的动态代理来创建代理对象,为啥会传入当前类**JdkDynamicAopProxy**
,因为当前类实现了**InvocationHandler**
接口。
因此,当代理对象调用目标方法的时候,就会执行该类的**invoke()**
。
8.代理对象执行目标方法
@Override
@Nullable
public Object invoke(Object proxy/*代理对象*/, Method method/*目标方法*/, Object[] args/*目标方法对应的参数*/) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
//advised 这里实际上就是proxyFactory的引用,targetSource 实际上就是上层传递封装的targetsource
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
/*如果代理类实现的接口里面有equals方法,就使用里面的,否则使用jdk提供的equals方法*/
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
//如果代理类实现的接口里面提供了hashcode方法,就是用里面的,否则用jdk的
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
/*暂时尚未用到,TODO*/
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
} else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
//返回值
Object retVal;
/**
* 是否需要将当前的代理对象设置在aop上下文中
* aop上下文对象实际上就是一个threadLocal
* 为什么要引入一个aop上下文?
* 目标对象A B
* 通过代理的方式调用A.eat()
* 这个eat方法里面有恰恰调用到了B的方法,这个时候B对象实际上并不是代理对象,所以
* b的方法执行前后并不会被增强,为了解决这个问题,就引入了aop的上下文
*/
if (this.advised.exposeProxy) {
// 将当前代理对象设置到aop上下文中,并返回老的代理对象
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
/*根据targetSource拿到目标对象*/
target = targetSource.getTarget();
/*根据目标对象拿到目标对象的类型*/
Class<?> targetClass = (target != null ? target.getClass() : null);
// 这里是最关键的地方,查找适合该方法的增强 具体是如何查找的?
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
/*查询出匹配当前方法拦截器的数量是0 说明当前方法不需要被增强,直接通过反射调用目标对象的目标方法。*/
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
/*调用目标对象的目标方法*/
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
/*说明有匹配当前method的方法拦截器,说明要做增强处理 */
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
/*核心驱动逻辑在ReflectiveMethodInvocation*/
retVal = invocation.proceed();
}
/*获取方法的返回值类型*/
Class<?> returnType = method.getReturnType();
/*如果目标方法返回目标对象 ,做一个替换 ,返回代理对象*/
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
//方法是void类型,但是返回值类型还不为空,说明有问题,抛异常
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 将上次设置的proxy在此设置回去到aop上下文内
//因为当前代理对象的目标方法已经完成了,需要回到上一层逻辑
//属于恢复现场的逻辑
AopContext.setCurrentProxy(oldProxy);
}
}
}
�
�抛开一切不是很重要的逻辑
判断当前代理对象是否应该暴露出去,aop上下文**AopContext**
实际上就是一个ThreadLocal。
为什么要引入AOP的上下文?
假设有目标对象A,B。
通过代理的方式调用A.eat()。
这个eat()方法里面恰恰调用了B的方法,这个时候对象实际上并不是代理对象,所以B的方法执行前后并不会被增强,为了解决这个问题,就引入了AOP上下文。
通过**getInterceptorsAndDynamicInterceptionAdvice()**
查找到当前方法执行前后需要执行的增强器。
�
如果当前方法匹配的增强器数量是0,那么直接通过反射调用目标方法。
否则说明有匹配的增强器,需要做增强处理。**retVal=ReflectiveMethodInvocation.proceed()**
retVal就是方法的返回值。
判断如果方法最终返回的目标对象,那就替换成代理对象。
判断如果方法是void类型,但是返回值类型还不为空,说明有问题,抛异常。
最终返回结果,并将AOP上下文的代理对象还原成里面原有的对象,因为当前代理对象的目标方法已经完成了,需要回到上一层逻辑。
�
�至此,AOP整个流程就分析完了,剩下的一些核心的细节:
**getInterceptorsAndDynamicInterceptionAdvice()**
查找到当前方法执行前后需要执行的增强器**retVal=ReflectiveMethodInvocation.proceed()**
执行增强器逻辑
通过前面的分析,我们大体上了解了Spring的Aop的执行流程。接下来我们在看一些核心的细节,如何查找目标方法的增强器。
9.查找增强器
**List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);**
�
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
//先尝试从缓存拿
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
/*如果缓存为空*/
if (cached == null) {
/*那就走查找逻辑,并刷新缓存
* advisorChainFactory什么时候创建的?
* 这个是在proxyFactory里面的一个变量,代理工厂创建出来,他就创建出来了
* */
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
/*最终返回查找到的值*/
return cached;
}
查找缓存,如果没命中则去查找并放入缓存放回。我们继续往下看查找逻辑**this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice()**
。
这个**advisorChainFactory**
是什么?看当前类的属性**AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();**
从这里我们就定位到了看哪个方法的逻辑
�
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config/*代理工厂*/, Method method/*目标方法*/, @Nullable Class<?> targetClass/*目标对象类型*/) {
/**
* 这个接口是切面适配器的注册中心
* 1.可以注册AdvisorAdapter 适配器目的:将非advisor类型的增强包装成advisor ,将advisor类型的增强提取出来对应的 方法拦截器
*
* */
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
/**
* 获取代理工厂内部持有的增强信息
* 1. addAdvice
* 2. addAdvisor
* 最终在代理工厂中都会包装成 advisor
* */
Advisor[] advisors = config.getAdvisors();
/*创建一个拦截器列表,长度就是advisor的长度*/
List<Object> interceptorList = new ArrayList<>(advisors.length);
/*真实的目标对象类型*/
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
/*引介增强相关*/
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
/*包含切点信息的增强,内部逻辑就是做匹配算法*/
if (advisor instanceof PointcutAdvisor) {
// 转换成 PointcutAdvisor 类型,可以获取到切点信息
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
/*条件二成立,说明当前被代理对象的class匹配当前advisor成功,可能被advisor增强,具体还要看方法匹配。 这里可以看一下 Pointcut 源码*/
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
/*获取切点信息的方法匹配器,做方法级别的匹配*/
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
/*引介相关的,不需要考虑*/
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
/*进行方法匹配 目标方法匹配成功 , match = true,当前的增强器可以应用到method*/
match = mm.matches(method, actualClass);
}
/*判断是否还需要运行时的匹配*/
if (match) {
/*提取出advisor类持有的拦截器信息 registry里面包含三个默认的增强器*/
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
/*如果是运行时匹配,那就走运行时匹配的逻辑*/
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
/*将方法拦截器追加到拦截器列表里面去*/
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
/*不考虑引介,所以直接跳过*/
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
/*适配所有方法的*/
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
/*返回所有匹配当前方法的拦截器*/
return interceptorList;
}
方法有点长,我们挑重点慢慢分析。
首先获取到切面适配器的注册中心,切面适配器**AdvisorAdapter**
是做什么的?
将非advisor类型的增强包装成advisor ,将advisor类型的增强提取出来对应的 方法拦截器。
获取代理工厂内部持有的增强信息
- Advice
- Advisor
最终在代理工厂中都会被包装成Advisor。
遍历所有的拦截器:
先是处理切点类型的增强器
- 先将增强器转化成
**PointcutAdvisor**
类型 - 判断如果当前被代理对象的class匹配增强器成功,说明可能增强成功,还要看具体的方法匹配,这里可以看一下
**PointCut**
源码 - 获取切点信息的方法匹配器,准备做方法级别的匹配
**match = mm.matches(method, actualClass)**
进行具体的方法匹配- 判断是否需要运行时匹配
- 如果需要,提取出增强器持有的拦截器信息(registry里面默认持有三个增强器),走运行时匹配的逻辑 -> 将
**InterceptorAndDynamicMethodMatcher**
加入到拦截器列表 - 如果不需要,将方法拦截器添加到拦截器列表
- 先将增强器转化成
处理引介类型的增强器
这里的逻辑我们不需要关注
处理适配所有方法的增强器
从增强器的适配中心获取所有的拦截器
最终返回匹配当前方法的所有拦截器
10.方法匹配
这里我们再看一下具体的方法匹配逻辑。
看一下**AbstractRegexpMethodPointcut**
,说实话,营养价值不大,有兴趣可以自行琢磨。
@Override
public boolean matches(Method method, Class<?> targetClass) {
return (matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass)) ||
(targetClass != method.getDeclaringClass() &&
matchesPattern(ClassUtils.getQualifiedMethodName(method, method.getDeclaringClass()))));
}
/**
* Match the specified candidate against the configured patterns.
* @param signatureString "java.lang.Object.hashCode" style signature
* @return whether the candidate matches at least one of the specified patterns
*/
protected boolean matchesPattern(String signatureString) {
for (int i = 0; i < this.patterns.length; i++) {
boolean matched = matches(signatureString, i);
if (matched) {
for (int j = 0; j < this.excludedPatterns.length; j++) {
boolean excluded = matchesExclusion(signatureString, j);
if (excluded) {
return false;
}
}
return true;
}
}
return false;
}
11.拦截器的核心驱动
获取到所有的匹配当前方法的拦截器后,最终我们是要驱动所有的拦截器去执行,接下来分析下拦截器的核心驱动逻辑。**invocation.proceed()**
,核心逻辑在**ReflectiveMethodInvocation**
中。
@Override
@Nullable
public Object proceed() throws Throwable {
// 因为从-1开始,如果当前拦截器下标 == 拦截器数量-1 ,说明所有方法拦截器都执行过了,接下来需要执行目标对象的目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
/*调用连接点*/
return invokeJoinpoint();
}
/*获取下一个方法拦截器*/
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
/*判断是否需要运行时匹配*/
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
/*大部分情况下会走到else这里静态匹配*/
else {
// 让当前方法拦截器执行invoke即可 ,并且将当前对象传递进去
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
判断是否所有拦截器都执行完了,如果是的话,执行目标方法**invokeJoinpoint()**
。
�获取下一个拦截器,判断是否需要做运行时匹配,大部分情况下,我们都是走静态匹配的逻辑。
让当前方法拦截器执行**invoke()**
。
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
通过这样类似递归的链式调用,每一个拦截器等待下一个拦截器执行完成返回以后在执行,拦截器的机制保证了通知方法与目标方法的执行顺序。
再来看下如何调用目标方法。**invokeJoinpoint()**
@Nullable
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
�继续往下追。
@Nullable
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method.
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}
最终通过暴力反射来调用目标方法执行。
12.切点表达式
**PointCut**
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never {@code null})
*
* 类过滤器:判断某个类是否符合切点位置
*/
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
* 方法匹配器:判断类中某个方法是否匹配条件,匹配条件的方法才会被增强
*/
MethodMatcher getMethodMatcher();
/**
* Canonical Pointcut instance that always matches.
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
前面案例代码中,有一个我们自己实现的切点,可以回顾一下。
最终回顾下开头的一张图,明确下**Advised --持有--> Advisor --持有--> Advice --子类-->Interceptor --子类-->MethodInterceptor**
关系:
至此,整个AOP的全部流程已经梳理清晰。下一篇,我们将开始分析Spring的事务。