摘要
深入研究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.findEligibleAdvisors
中sortAdvisors
以前的結果:
AbstractAdvisorAutoProxyCreator.findEligibleAdvisors
中sortAdvisors
以后的結果:
经观查,新版本的次序沒有转变
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
方式 开展较为,为此来分辨加上到谁的smallerObjects
和biggerObjects
里边
有关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)
因此便是依照这一次序来排列的
汇总
-
是由于造成次序不一致的呢?是spring的版本号造成的,如下图:
-
低版授予了优先,而高版本号的沒有授予优先,选用的默认设置次序,那麼默认设置顺序是什么呢,如下图:
关注不迷路
扫码下方二维码,关注宇凡盒子公众号,免费获取最新技术内幕!
评论0