对于同一个连接点,切面与通知的执行顺序有很多种的可能性,我们来分情况进行讨论。
- 同一个切面,同一种通知类型
网上有很多的教程说在这种情况下,通知的执行顺序是无法确定的,或者有的说是按照通知的申明顺序执行的,其实通过实际测试都是不准确的。
例:
在上面这个例子中,我们定义了两个前置通知,切入点都是一样的,那么它的执行顺序是怎样的呢?
可以看到控制台的输出是先执行了第一个通知,后执行了第二个通知,似乎是按照通知的申明顺序执行的,但是我们现在将通知的方法名改一下:
再来看一下控制台的输出,可以看到,它并不是按照申明顺序来执行了,而是先执行了第二个通知,然后在执行第一个通知。
我们观察一下这两个通知方法的名称,前面的before都是一样的,后面一个是one一个是four,难道它跟这个单词的意义有关?数字越大越先执行?我们再看下面这个例子:
这个时候我们标注的这两个通知方法名before后面一个是five,一个是ten,如果按照前面的例子推断,应该是ten先执行,也就说第二个通知先执行,第一个通知后执行,我们看一下控制台输出:
可以看到结果恰恰相反,第一个通知先执行了,所以说这个执行的先后顺序是跟名称中数字大小无关的,那么是不是就无法确定它的执行顺序了呢?
我们来看一个例子:
在这个例子中两个通知方法的名字一个是beforer,一个是before_,那么这个时候执行的顺序是先执行第二个通知,再执行第一个通知。
如果修改一下:
那么它的执行顺序会变成先执行第一个通知,再执行第二个通知,我们只是修改了通知方法的名字,将第一个通知的方法名由beforer改成了before0。
所以我们可以看到其实这个执行顺序肯定是跟这个方法名有关系的,那么到底是什么关系呢。
我们查一下ASCII码,r的十进制码是114,_的十进制码是95,0的十进制码是48,有意思的地方就出现了,0的十进制码 > _的十进制码 > r的十进制码,我们观察下下面这个例子:
然后看一下执行顺序:
这个执行顺序是不是按照十进制码从小到大来执行的?我们可以进一步去验证,比如我现在将第二个通知的名称改为befores,s的十进制码是115,是大于r的十进制码的,所以befores这个通知方法应该后于beforer执行,也就说上面的执行顺序应该变为 前置通知1,前置通知3,前置通知2,我们来验证一下:
再接下来,我们还可以不改名字,直接调整申明的顺序,比如我们现在将第三个通知放到第一个位置申明,看看执行顺序是否会变化:
可以看到执行的顺序是没有变化的,所以说对于同一个连接点而言,同一个切面里同样类型的通知的执行顺序,实际上是根据通知方法的名称中字母的ASCII码大小决定的,码越小越先执行,码越大越后执行。
在比较的时候,它是根据方法名逐字母去比较的,比如说我们上面那三个方法,它们的名字前面都是一样的,所以就会去比较最后一个字符,如果我们现在将第三个通知方法的第一个字母改成a,因为a的十进制码是大于b的,所以修改后,第三个通知应该是第一个被执行。
最后总结下,在这种情况下,通知的执行顺序是按照方法名,从左往右依次逐字符比较的,只要有一个位置的字符能够确定顺序(也就是不一样),那么就不会再往下比较了,直接根据这个位置两个方法名中字符的ACSII码大小决定通知执行的顺序,ACSII码越小的通知越先执行。