深入探究Spring AOP源码

摘要

深入研究Spring AOP源代码,揭开高低版本Advice排列的面纱,探究排序方式变更的原因。解决文件目录问题,分析AbstractAdvisorAutoProxyCreator.sortAdvisors()方法的影响。科学研究Spring,探索其中奥秘。

正文

依照自身的构思科学研究Spring AOP源代码【2】

研究Spring高版本号和低版针对Advice排列的不一样,一步步地解开其面具,包含了高矮版本号中间的详尽比照及其缘故。

文件目录

  • 难题的明确提出
  • 哪一步造成了次序的更改
  • AbstractAdvisorAutoProxyCreator.sortAdvisors()方式
  • 汇总

难题的明确提出

依照自身的构思科学研究Spring AOP源代码【1】   本文详细介绍了Spring AOP源代码的关键步骤,依据本文最终明确提出的难题,大家来讨论一下为何通告次序是不一样的。

最先大家看一下最新版本(5.3.5-SNAPSHOT)的通告次序与輸出結果,如下图:

次序:Around Before After AfterReturning

輸出以下:
===== Around before =====
===== Before =====
do service
===== AfterReturning =====
===== After =====
===== Around after =====

大家再看来一下旧版(5.2.6.RELEASE)的通告次序与輸出結果,如下图:

次序:AfterReturning After Around Before

===== Around before =====
===== Before =====
do service
===== Around after =====
===== After =====
===== AfterReturning =====
  • 大家见到不一样的次序是对結果的輸出也是有影响的

  • 还有一个便是对After通告是不是实行的危害,大家都了解After通告的界定是无论方式 是否有抛出现异常,它都是会实行
    可是如果我们在Before通告或是Around通告中抛一个出现异常,那上边的二种排列针对After通告是不是实行是不一样的,实际的实行結果大家看来一下:

大家先往Before通告中抛一个出现异常,编码以下:

@Before("pointCut()")
public void methodBefore() {
    System.out.println("===== Before =====");
    throw new RuntimeException();
}

下边是不一样版本号的实行結果:

最新版本以下:
===== Around before =====
===== Before =====
Exception in thread "main" java.lang.RuntimeException

老版本以下:
===== Around before =====
===== Before =====
===== After =====
Exception in thread "main" java.lang.RuntimeException

从上边的結果能够看得出,最新版本的After通告是沒有实行的,而老版本的After通告是实行了的,这就是通告次序所造成的不良影响,因此朋友们在开发设计时遇到该类难题时,能够往这些方面想一想喔~

哪一步造成了次序的更改

大家以旧版来debug,缘故到后边就知道,因此下列的debug步骤是根据旧版的,大家讨论一下这一次序是一直不会改变的呢,或是在某一方式 实行以后发生了转变

大家就从JdkDynamicAopProxy.invoke逐渐,一步一步的debug,一起来看一下次序的转变。

debug的情况下,有一个极为便捷的方法,那便是:我绘制的那一个标志:drop frame,这一作用便是回到上一个涵数,那样的话就无需再次运作随后再次切断点,就等同于一个孟婆汤,果真程序流程的全球和实际的全球是不一样的,你能肆无忌惮,好,我们要搞好充分准备逐渐debug了。

最先,大家看一下这一chain是怎么转化成的,进到AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice

我们可以见到这一链根据getInterceptorsAndDynamicInterceptionAdvice方式 得到,并放进了一个缓存文件里

进到DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice

见到有一个advisors二维数组,最后的链便是依据这一二维数组获得的,发觉这一次序便是最后次序,能够见到这一二维数组是由config.getAdvisors()获得的

进到AdvisedSupport.getAdvisors

我们可以见到回到的二维数组是this.advisorArray,那大家来猜一下谁会把这个二维数组添充好

试着在AdvisedSupport这一类里检索addAdvisor,发觉有11处:

在这种地区都打上中断点,随后再次运作,看一下实际会运作到哪一个部位

发觉是在AdvisedSupport.addAdvisors(Advisor... advisors)这一方式 :

这一步的結果或是最后次序,大家想知道谁启用了这一方式 ,此刻就可以用drop frame

能够见到在AbstractAutoProxyCreator.createProxy启用了此方式 :

能够见到数据信息是由specificInterceptors获得的,而且依然是最后次序,再次drop frame

能够见到在AbstractAutoProxyCreator.wrapIfNecessary启用了此方式 :

能够见到启用getAdvicesAndAdvisorsForBean这一方式 得到了二维数组

进到AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean这一方式 :

进到AbstractAdvisorAutoProxyCreator.findEligibleAdvisors这一方式 :

在这儿,大家发觉次序和最后次序不一样了,终于找到你

看来一下后边的回到結果:

从上边的結果,我们可以猜想是sortAdvisors这一方式 更改了次序

进到AbstractAdvisorAutoProxyCreator.sortAdvisors这一方式 :

从图中能够看得出,是PartialOrder.sort(partiallyComparableAdvisors)这一方式 更改了次序

为了更好地确定一下,大家看一下新版本的次序是如何的

AbstractAdvisorAutoProxyCreator.findEligibleAdvisorssortAdvisors以前的結果:

AbstractAdvisorAutoProxyCreator.findEligibleAdvisorssortAdvisors以后的結果:

经观查,新版本的次序沒有转变

AbstractAdvisorAutoProxyCreator.sortAdvisors()方式

如今我们知道是哪个地方把次序更改了,那大家就看一下PartialOrder.sort这一方式

public class PartialOrder {
	public static <T extends PartialComparable> List<T> sort(List<T> objects) {
		// lists of size 0 or 1 don't need any sorting
		if (objects.size() < 2) {
			return objects;
		}

		// ??? we might want to optimize a few other cases of small size

		// ??? I don't like creating this data structure, but it does give good
		// ??? separation of concerns.
		List<SortObject<T>> sortList = new LinkedList<SortObject<T>>();
		for (Iterator<T> i = objects.iterator(); i.hasNext();) {
			addNewPartialComparable(sortList, i.next());
		}

		// System.out.println(sortList);

		// now we have built our directed graph
		// use a simple sort algorithm from here
		// can increase efficiency later
		// List ret = new ArrayList(objects.size());
		final int N = objects.size();
		for (int index = 0; index < N; index  ) {
			// System.out.println(sortList);
			// System.out.println("-->"   ret);

			SortObject<T> leastWithNoSmallers = null;

			for (SortObject<T> so: sortList) {
				if (so.hasNoSmallerObjects()) {
					if (leastWithNoSmallers == null || so.object.fallbackCompareTo(leastWithNoSmallers.object) < 0) {
						leastWithNoSmallers = so;
					}
				}
			}

			if (leastWithNoSmallers == null) {
				return null;
			}

			removeFromGraph(sortList, leastWithNoSmallers);
			objects.set(index, leastWithNoSmallers.object);
		}

		return objects;
	}
}

最先看一下下边的编码:

List<SortObject<T>> sortList = new LinkedList<SortObject<T>>();
for (Iterator<T> i = objects.iterator(); i.hasNext();) {
    addNewPartialComparable(sortList, i.next());
}

大家从上边的编码能够见到,它为会每一个advice结构一个SortObject构造:

private static class SortObject<T extends PartialComparable> {
    T object;
    List<SortObject<T>> smallerObjects = new LinkedList<SortObject<T>>();
    List<SortObject<T>> biggerObjects = new LinkedList<SortObject<T>>();
}

object是它自身自身,smallerObjects包括了比它优先高的advice,biggerObjects包括了比它优先低的advice

大家看一下结构結果是那样的:

依据这一构造,它是怎么排序的呢?看以下编码:

		final int N = objects.size();
		for (int index = 0; index < N; index  ) {
			// System.out.println(sortList);
			// System.out.println("-->"   ret);

			SortObject<T> leastWithNoSmallers = null;

			for (SortObject<T> so: sortList) {
				if (so.hasNoSmallerObjects()) {
					if (leastWithNoSmallers == null || so.object.fallbackCompareTo(leastWithNoSmallers.object) < 0) {
						leastWithNoSmallers = so;
					}
				}
			}

			if (leastWithNoSmallers == null) {
				return null;
			}

			removeFromGraph(sortList, leastWithNoSmallers);
			objects.set(index, leastWithNoSmallers.object);
		}
		boolean hasNoSmallerObjects() {
			return smallerObjects.size() == 0;
		}

每一次寻找smallerObjects目标size为0的目标,也就是这时它是优先最大的

从上边的結果图能够看得出,最先是ExposeInvocationInterceptor这一类,这一类是个拓展的advisor,它优先最大,因此它的smallerObjects的尺寸为0,
因此它的次序就是0,它被谈妥以后,便会被移祛除,他人的smallerObjects和biggerObjects会把它移祛除,
随后AspectJAfterReturningAdvice的smallerObjects便会删掉它,它的smallerObjects的size便会变为0,以后它便是次序1
依次类推,AspectJAfterAdvice为次序2 AspectJAroundAdvice为次序3 最终AspectJMethodBeforeAdvice为次序4。

那大家再看来一下SortObject是怎么转化成的,看下面的编码:

public class PartialOrder {
      	private static <T extends PartialComparable> void addNewPartialComparable(List<SortObject<T>> graph, T o) {
      		SortObject<T> so = new SortObject<T>(o);
      		for (Iterator<SortObject<T>> i = graph.iterator(); i.hasNext();) {
      			SortObject<T> other = i.next();
      			so.addDirectedLinks(other);
      		}
      		graph.add(so);
      	}
}

private static class SortObject<T extends PartialComparable> {
	void addDirectedLinks(SortObject<T> other) {
		int cmp = object.compareTo(other.object);
		if (cmp == 0) {
			return;
		}
		if (cmp > 0) {
			this.smallerObjects.add(other);
			other.biggerObjects.add(this);
		} else {
			this.biggerObjects.add(other);
			other.smallerObjects.add(this);
		}
	}
}

从上边编码,我们可以看得出,实际上便是依据compareTo方式 开展较为,为此来分辨加上到谁的smallerObjectsbiggerObjects里边

有关compareTo的启用,最后追踪到以下方式 (同一切面下advice优先的较为):

class AspectJPrecedenceComparator implements Comparator<Advisor> {
	private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
		boolean oneOrOtherIsAfterAdvice =
				(AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));
		int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2);

		if (oneOrOtherIsAfterAdvice) {
			// the advice declared last has higher precedence
			if (adviceDeclarationOrderDelta < 0) {
				// advice1 was declared before advice2
				// so advice1 has lower precedence
				return LOWER_PRECEDENCE;
			}
			else if (adviceDeclarationOrderDelta == 0) {
				return SAME_PRECEDENCE;
			}
			else {
				return HIGHER_PRECEDENCE;
			}
		}
		else {
			// the advice declared first has higher precedence
			if (adviceDeclarationOrderDelta < 0) {
				// advice1 was declared before advice2
				// so advice1 has higher precedence
				return HIGHER_PRECEDENCE;
			}
			else if (adviceDeclarationOrderDelta == 0) {
				return SAME_PRECEDENCE;
			}
			else {
				return LOWER_PRECEDENCE;
			}
		}
	}

	private int getAspectDeclarationOrder(Advisor anAdvisor) {
		AspectJPrecedenceInformation precedenceInfo =
			AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor);
		if (precedenceInfo != null) {
			return precedenceInfo.getDeclarationOrder();
		}
		else {
			return 0;
		}
	}
}

public abstract class InstantiationModelAwarePointcutAdvisorImpl {
	@Override
	public int getDeclarationOrder() {
		return this.declarationOrder;
	}
}

能够见到,实际上较为的便是declarationOrder这一字段名

根据查询启用链,查询在哪儿取值了这一字段名,如下图:

发觉是ReflectiveAspectJAdvisorFactory.getAdvisors中赋的值,如下图:

在老版中,取值的尺寸是advisors的size

因为advisor一个一个的被加上进来的,因此他们的值先后是0,1,2,3,认证結果如下图:

大家再看来一下新版本的取值:

大家见到新版本的取值都是0,那样的话,那大伙儿的优先全是一样的,因此便是依照默认设置次序来开展实行的,

那这一默认设置的次序也是如何来的呢

通告是以横切面的advice方式 获取出去的,并干了一下排列,实际以下:

看来一下排列的电压比较器:

那麼电压比较器是怎么较为的呢

public class ConvertingComparator<S, T> implements Comparator<S> {
	@Override
	public int compare(S o1, S o2) {
		T c1 = this.converter.convert(o1);
		T c2 = this.converter.convert(o2);
		return this.comparator.compare(c1, c2);
	}
}

public class InstanceComparator<T> implements Comparator<T> {
	@Override
	public int compare(T o1, T o2) {
		int i1 = getOrder(o1);
		int i2 = getOrder(o2);
		return (Integer.compare(i1, i2));
	}

	private int getOrder(@Nullable T object) {
		if (object != null) {
			for (int i = 0; i < this.instanceOrder.length; i  ) {
				if (this.instanceOrder[i].isInstance(object)) {
					return i;
				}
			}
		}
		return this.instanceOrder.length;
	}

	public InstanceComparator(Class<?>... instanceOrder) {
		Assert.notNull(instanceOrder, "'instanceOrder' array must not be null");
		this.instanceOrder = instanceOrder;
	}
}

从上边能够剖析出,便是在instanceOrder这一二维数组里边的部位,而这一也是根据下边的构造方法取值的
new InstanceComparator<>(Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class)
因此便是依照这一次序来排列的

汇总

  1. 是由于造成次序不一致的呢?是spring的版本号造成的,如下图:

  2. 低版授予了优先,而高版本号的沒有授予优先,选用的默认设置次序,那麼默认设置顺序是什么呢,如下图:

关注不迷路

扫码下方二维码,关注宇凡盒子公众号,免费获取最新技术内幕!

温馨提示:如果您访问和下载本站资源,表示您已同意只将下载文件用于研究、学习而非其他用途。
文章版权声明 1、本网站名称:宇凡盒子
2、本站文章未经许可,禁止转载!
3、如果文章内容介绍中无特别注明,本网站压缩包解压需要密码统一是:yufanbox.com
4、本站仅供资源信息交流学习,不保证资源的可用及完整性,不提供安装使用及技术服务。点此了解
5、如果您发现本站分享的资源侵犯了您的权益,请及时通知我们,我们会在接到通知后及时处理!提交入口
0

评论0

请先

站点公告

🚀 【宇凡盒子】全网资源库转储中心

👉 注册即送VIP权限👈

👻 全站资源免费下载✅,欢迎注册!

记得 【收藏】+【关注】 谢谢!~~~

立即注册
没有账号?注册  忘记密码?

社交账号快速登录