上面我们讨论了一个切面的运行,而事实上Spring还可以支持多个切面的运行。在组织多个切面的时候,我们需要知道其运行的顺序,首先我们创建3个切面类,如下代码所示

package cn.hctech2006.boot.bootaop.aspect;

import org.aspectj.lang.annotation.*;

@Aspect
public class MyAspect1 {
@Pointcut("execution(* cn.hctech2006.boot.bootaop.service.impl.UserServiceImpl.manyAspects())")
public void pointCut(){

}
@Before("pointCut()")
public void before(){
System.out.println("MyAspect1 before....");
}
@After("pointCut()")
public void after(){
System.out.println("MyAspect1 after......");
}
@AfterReturning("pointCut()")
public void afterReturning(){
System.out.println("MyAspect1 afterReturning......");
}
}
package cn.hctech2006.boot.bootaop.aspect;

import org.aspectj.lang.annotation.*;

@Aspect
public class MyAspect2 {
@Pointcut("execution(* cn.hctech2006.boot.bootaop.service.impl.UserServiceImpl.manyAspects())")
public void pointCut(){

}
@Before("pointCut()")
public void before(){
System.out.println("MyAspect2 before....");
}
@After("pointCut()")
public void after(){
System.out.println("MyAspect2 after......");
}
@AfterReturning("pointCut()")
public void afterReturning(){
System.out.println("MyAspect2 afterReturning......");
}
}
package cn.hctech2006.boot.bootaop.aspect;

import org.aspectj.lang.annotation.*;

@Aspect
public class MyAspect3 {
@Pointcut("execution(* cn.hctech2006.boot.bootaop.service.impl.UserServiceImpl.manyAspects())")
public void pointCut(){

}
@Before("pointCut()")
public void before(){
System.out.println("MyAspect3 before....");
}
@After("pointCut()")
public void after(){
System.out.println("MyAspect3 after......");
}
@AfterReturning("pointCut()")
public void afterReturning(){
System.out.println("MyAspect3 afterReturning......");
}
}

这样就存在了三个切面,他们同时拦截USerServiceImpl的manyAspect方法,所以我们现在就来实现这个新的方法,代码如下:

() {
System.out.println("测试多个切面的顺序");
}

同期,需要改造UserService接口提供manyAspects方法。这个过程比较简单,这里就不演示这个过程。接着在UserController这个控制器加入新的方法,对于多个切面进行测试,如代码清单所示:

("/manytAspects")
public String manyAspects(){
userService.manyAspects();
return "manyAspects";
}

这样我们就带调用了UserServcieImpl的manyAspect方法,然后配置文件加入这三个切面的Bean

package cn.hctech2006.boot.bootaop;

@SpringBootApplication(scanBasePackages = {"cn.hctech2006.boot.bootaop.*"})
public class BootAopApplication {

//定义切面
@Bean(name = "myAspect")
public MyAspect initMyAspect(){
return new MyAspect();
}
//定义切面
@Bean(name = "myAspect1")
public MyAspect1 initMyAspect1(){
return new MyAspect1();
}
//定义切面
@Bean(name = "myAspect2")
public MyAspect2 initMyAspect2(){
return new MyAspect2();
}
//定义切面
@Bean(name = "myAspect3")
public MyAspect3 initMyAspect3(){
return new MyAspect3();
}
//启动切面
public static void main(String[] args) {
SpringApplication.run(BootAopApplication.class, args);
}

}

运行这三个文件就可以看到Tomcat运行的日志,待到启动好了之后,在浏览器输入http://localhost:8241/user/manyAspects,,可以在日志看到

MyAspect1 before....
MyAspect2 before....
MyAspect3 before....
测试多个切面的顺序
MyAspect3 after......
MyAspect3 afterReturning......
MyAspect2 after......
MyAspect2 afterReturning......
MyAspect1 after......
MyAspect1 afterReturning......

很多时候开发者需要确定切面的执行顺序,来决定那些切面先执行,那些切面后执行。为此,Spring提供了一个注解@Order和一个接口Ordered,我们可以使用他们的任意一个指定切面的顺序,下面我们先展示@Order,例如,我们指定MyAspect3的顺序是1,代码如下:

@Aspect
@Order(1)
public class MyAspect3 {}

同样的我们也可以指定MyAspect2的顺序是2,MyAspect1的顺序是3,这样我们再次测试就可以得到下面的日志:

MyAspect3 before....
MyAspect2 before....
MyAspect1 before....
测试多个切面的顺序
MyAspect1 after......
MyAspect1 afterReturning......
MyAspect2 after......
MyAspect2 afterReturning......
MyAspect3 after......
MyAspect3 afterReturning......

我们可以看到,对于前置通知(Before)都是按照@Order顺序从小到大运行的,而对于后置通知和返回通知都是按照Order顺序从大到小运行,这就是一个典型的责任链模式的顺序。同样的,使用Orderd接口也可以指定顺序。代码如下:

package cn.hctech2006.boot.bootaop.aspect;

import org.aspectj.lang.annotation.*;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

@Aspect
//@Order(1)
public class MyAspect3 implements Ordered {
@Override
public int getOrder() {
return 1;
}
@Pointcut("execution(* cn.hctech2006.boot.bootaop.service.impl.UserServiceImpl.manyAspects())")
public void pointCut(){

}
@Before("pointCut()")
public void before(){
System.out.println("MyAspect3 before....");
}
@After("pointCut()")
public void after(){
System.out.println("MyAspect3 after......");
}
@AfterReturning("pointCut()")
public void afterReturning(){
System.out.println("MyAspect3 afterReturning......");
}


}

其他的同样类似,不再赘言,同时推荐使用@Order注解。