约定编程Spring AOP-多个切面
原创
©著作权归作者所有:来自51CTO博客作者wx5cb71f4b705da的原创作品,请联系作者获取转载授权,否则将追究法律责任
上面我们讨论了一个切面的运行,而事实上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注解。