zoukankan      html  css  js  c++  java
  • 【源码】按照自己的思路研究Spring AOP源码 ②

    问题的提出

    按照自己的思路研究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. 低版本赋予了优先级,而高版本的没有赋予优先级,采用的默认顺序,那么默认循序是什么呢,如下图:

  • 相关阅读:
    hlgoj 1766 Cubing
    Reverse Linked List
    String to Integer
    Bitwise AND of Numbers Range
    Best Time to Buy and Sell Stock III
    First Missing Positive
    Permutation Sequence
    Next Permutation
    Gray Code
    Number of Islands
  • 原文地址:https://www.cnblogs.com/eaglelihh/p/14751827.html
Copyright © 2011-2022 走看看