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

  • 相关阅读:
    itk_interior
    itk_option define
    scrolled canvas tcl tk
    init.rc的disabled含义
    WIFI分析与移植
    ubuntu10.04命令挂载windows硬盘与U盘
    Android WIFI 分析
    Android WIFI 分析
    Android平台开发WIFI function portingWIFI功能移植
    Android平台开发WIFI function portingWIFI功能移植
  • 原文地址:https://www.cnblogs.com/eaglelihh/p/14751827.html
Copyright © 2011-2022 走看看