spring学习笔记(10)@AspectJ研磨分析[3]增强织入顺序实例详解
2016-03-22 09:46
711 查看
增强的织入顺序
当一个连接点同时织入多个增强时,就存在顺序调用问题:1. 增强在同一个切面类中定义:依照增强在切面类中定义的顺序依次织入。
2. 增强位于不同的切面,但果这些切面都实现了org.springframework.core.Ordered
接口,则由接口注解的顺序号决定,顺序号越小,对于不同的增强,织入顺序为:
1. 前置增强->越先织入
2. 后置增强->越后织入
3. 最终增强->越后织入
4. 环绕增强->调用原方法之前的部分先织入,调用原方法之后的部分后织入
我们先来看一个实例:
1.目标对象
package test.aop2; public class UserController { public void login(String name){ System.out.println("I'm "+name+" ,I'm logining"); } }
2. 切面配置
/*-----------------------有序切面类1--------------------------*/ @Aspect public class Annotation_aspect implements Ordered {//实现顺序接口 @Pointcut("target(test.aop2.UserController)") private void pointcut(){}//定义切点 @AfterThrowing("pointcut()")//后置增强 public void AfterThrowing() throws Throwable{ System.out.println("Annotation_aspect 实施AfterThrowing,优先级为" + getOrder()); } @After("pointcut()")//最终增强 public void after() throws Throwable{ System.out.println("Annotation_aspect 实施after,优先级为" + getOrder()); } @Before("pointcut()")//前置增强 public void before() throws Throwable{ System.out.println("Annotation_aspect 实施@before,优先级为" + getOrder()); } @Around("pointcut()")//环绕增强 public void around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("Annotation_aspect 实施around前,优先级为" + getOrder()); joinPoint.proceed(); System.out.println("Annotation_aspect 实施around后,优先级为" + getOrder()); } @Override public int getOrder() { return 1; } } /*-----------------------有序切面类2--------------------------*/ @Aspect public class Annotation_aspect2 implements Ordered { @Pointcut("target(test.aop2.UserController)") private void pointcut(){} @AfterThrowing("pointcut()") public void AfterThrowing() throws Throwable{ System.out.println("Annotation_aspect2 实施AfterThrowing,优先级为" + getOrder()); } @After("pointcut()") public void after() throws Throwable{ System.out.println("Annotation_aspect2 实施after,优先级为" + getOrder()); } @Before("pointcut()") public void before() throws Throwable{ System.out.println("Annotation_aspect2 实施@before,优先级为" + getOrder()); } @Around("pointcut()") public void around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("Annotation_aspect2 实施around前,优先级为" + getOrder()); joinPoint.proceed(); System.out.println("Annotation_aspect2 实施around后,优先级为" + getOrder()); } @Override public int getOrder() { return 2; } } /*-----------------------无序切面类1--------------------------*/ @Aspect public class noOrder_aspect { @Pointcut("target(test.aop2.UserController)") private void pointcut(){} @AfterThrowing("pointcut()") public void AfterThrowing() throws Throwable{ System.out.println("noOrder_aspect 实施AfterThrowing,无优先级"); } @After("pointcut()") public void after() throws Throwable{ System.out.println("noOrder_aspect 实施after,无优先级"); } @Before("pointcut()") public void before() throws Throwable{ System.out.println("noOrder_aspect 实施@before,无优先级"); } @Around("pointcut()") public void around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("noOrder_aspect 实施around前,无优先级"); joinPoint.proceed(); System.out.println("noOrder_aspect 实施around后,无优先级"); } } /*-----------------------无序切面类2--------------------------*/ @Aspect public class noOrder_aspect2 { @Pointcut("target(test.aop2.UserController)") private void pointcut(){} @AfterThrowing("pointcut()") public void AfterThrowing() throws Throwable{ System.out.println("noOrder_aspect2 实施AfterThrowing,无优先级"); } @After("pointcut()") public void after() throws Throwable{ System.out.println("noOrder_aspect2 实施after,无优先级"); } @Before("pointcut()") public void before() throws Throwable{ System.out.println("noOrder_aspect2 实施@before,无优先级"); } @Around("pointcut()") public void around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("noOrder_aspect1 实施around前,无优先级"); joinPoint.proceed(); System.out.println("noOrder_aspect1 实施around后,无优先级"); } }
3. IOC容器配置
<aop:aspectj-autoproxy /> <!-- 使@AspectJ注解生效 --> <bean class="test.aop2.noOrder_aspect" /> <bean class="test.aop2.noOrder_aspect2" /> <bean class="test.aop2.Annotation_aspect2" /> <bean class="test.aop2.Annotation_aspect" /> <bean id="userController" class="test.aop2.UserController" /><!-- 注册目标对象 -->
4. 测试方法
public static void main(String args[]) throws Exception{ ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:test/aop2/aop.xml"); UserController userController = (UserController) ac.getBean("userController"); User user = new User(); userController.login("zenghao"); }
运行测试方法,控制台输出:
Annotation_aspect 实施around前,优先级为1
Annotation_aspect 实施@before,优先级为1
Annotation_aspect2 实施around前,优先级为2
Annotation_aspect2 实施@before,优先级为2
noOrder_aspect 实施around前,无优先级
noOrder_aspect 实施@before,无优先级
noOrder_aspect1 实施around前,无优先级
noOrder_aspect2 实施@before,无优先级
I’m zenghao ,I’m logining
noOrder_aspect1 实施around后,无优先级
noOrder_aspect2 实施after,无优先级
noOrder_aspect2 实施AfterReturning,无优先级
noOrder_aspect 实施around后,无优先级
noOrder_aspect 实施after,无优先级
noOrder_aspect 实施AfterReturning,无优先级
Annotation_aspect2 实施around后,优先级为2
Annotation_aspect2 实施after,优先级为2
Annotation_aspect2 实施AfterReturning,优先级为2
Annotation_aspect 实施around后,优先级为1
Annotation_aspect 实施after,优先级为1
Annotation_aspect 实施AfterReturning,优先级为1
针对以上信息,我们再复述前面结论来对比看,是完全符合的,顺序号越小,对于不同的增强,织入顺序为:
1. 前置增强->越先织入
2. 后置增强->越后织入
3. 最终增强->越后织入
4. 环绕增强->调用原方法之前的部分先织入,调用原方法之后的部分后织入
认真观察,我们还会发现:
1. 同一切面中,不同增强的织入顺序为:环绕增强前半部分->前置增强->元目标函数调用->环绕增强后半部分->最终增强->后置增强。
2. 没有实现order接口的“优先级”总是低于实现了order接口的,如针对前置增强来看,顺序为:
Annotation_aspect > Annotation_aspect2 > noOrder_aspect > noOrder_aspect
3. 先观察无序接口,我们会发现noOrder_aspect的优先级总是高于noOrder_aspect2的优先级,这是有前面IOC容器中前面Bean的配置顺序决定的:
<bean class="test.aop2.noOrder_aspect" /> <bean class="test.aop2.noOrder_aspect2" /> <bean class="test.aop2.Annotation_aspect2" /> <bean class="test.aop2.Annotation_aspect" />
那么,对于同样实现了order接口的切面,它们是否也满足这个规律呢?我们把Annotation_aspect2的优先级也设为1,然后运行测试函数,打印信息如下:
Annotation_aspect2 实施around前,优先级为1
Annotation_aspect2 实施@before,优先级为1
Annotation_aspect 实施around前,优先级为1
Annotation_aspect 实施@before,优先级为1
noOrder_aspect 实施around前,无优先级
noOrder_aspect 实施@before,无优先级
noOrder_aspect1 实施around前,无优先级
noOrder_aspect2 实施@before,无优先级
I’m zenghao ,I’m logining
noOrder_aspect1 实施around后,无优先级
noOrder_aspect2 实施after,无优先级
noOrder_aspect2 实施AfterReturning,无优先级
noOrder_aspect 实施around后,无优先级
noOrder_aspect 实施after,无优先级
noOrder_aspect 实施AfterReturning,无优先级
Annotation_aspect 实施around后,优先级为1
Annotation_aspect 实施after,优先级为1
Annotation_aspect 实施AfterReturning,优先级为1
Annotation_aspect2 实施around后,优先级为1
Annotation_aspect2 实施after,优先级为1
Annotation_aspect2 实施AfterReturning,优先级为1
关注粗体部分,是不是优先级和IOC容器的配置顺序对应上了,感兴趣的同学可以把两个没有实现order接口的配置顺序也交换一下,观察它们的织入优先级是否也跟着变化了。
除了实现org.springframework.core.Ordered配置顺序外,我们还可以使用注解@org.springframework.core.annotation.Order(优先级整数)来实现同样的效果。在这里,如果既使用注解,又使用接口实现的,且它们的优先级一致时,一样是看IOC容器的bean顺序,如:
<!-- <bean class="test.aop2.noOrder_aspect" /> <bean class="test.aop2.noOrder_aspect2" /> --> <bean class="test.aop2.Annotation_aspect3" /> <bean class="test.aop2.Annotation_aspect4" /> <bean class="test.aop2.Annotation_aspect2" /> <bean class="test.aop2.Annotation_aspect" />
其中Annotation_aspect3和Annotation_aspect4的类定义头部为:
@Aspect @Order(1) public class Annotation_aspect3{ .... } @Aspect @Order(2) public class Annotation_aspect4{ .... }
注释再次运行测试程序,得到打印信息:
Annotation_aspect3 实施around前,注解优先级为1
Annotation_aspect3 实施@before,注解优先级为1
Annotation_aspect 实施around前,优先级为1
Annotation_aspect 实施@before,优先级为1
Annotation_aspect4 实施around前,注解优先级为2
Annotation_aspect4 实施@before,注解优先级为2
Annotation_aspect2 实施around前,优先级为2
Annotation_aspect2 实施@before,优先级为2
I’m zenghao ,I’m logining
Annotation_aspect2 实施around后,优先级为2
Annotation_aspect2 实施after,优先级为2
Annotation_aspect2 实施AfterReturning,优先级为2
Annotation_aspect4 实施around后,注解优先级为2
Annotation_aspect4 实施after,注解优先级为2
Annotation_aspect4 实施AfterReturning,注解优先级为2
Annotation_aspect 实施around后,优先级为1
Annotation_aspect 实施after,优先级为1
Annotation_aspect 实施AfterReturning,优先级为1
Annotation_aspect3 实施around后,注解优先级为1
Annotation_aspect3 实施after,注解优先级为1
Annotation_aspect3 实施AfterReturning,注解优先级为1
观察IOC容器的配置顺序,这里也是对应上的。
综上,我们得到结论:多个同一类型的增强(如都是前置增强)对同一连接点的织入顺序是:配置有优先级看谁优先级高,优先级相同则看谁先在IOC容器注册,配置了order接口或注释的增强优先级总是高于没配置的。
通过以上分析,我们能够较好地总结出我们常用增强对应各种情况的织入顺序。在了解这些织入顺序后,有助于我们更灵活地将AOP运用到我们的项目中。
相关文章推荐
- spring学习笔记(11)@AspectJ研磨分析[2]切点表达式函数详解
- Server 对象 错误 \'ASP 0178 : 80070005\'
- asp Session 串号的解决方法
- spring学习笔记(10)@AspectJ研磨分析[1]入门、注解基本介绍
- 关于asp.net mvc项目部署到云服务器的一些经验分享
- .NET/ASP.NET 4.5 Bundle组件(捆绑、缩小静态文件)
- NET/ASP.NET Routing路由(深入解析路由系统架构原理)(转载)
- 【ASP.NET MVC路由测试+性能调试工具】
- ASP.NET动态生成GridView的使用
- ASP.NET Web Projects
- html+asp.net上传文件
- ASP.NET 一般处理程序
- ASP.NET Web API与Owin OAuth:调用与用户相关的Web API(三)
- ASP.NET Web API与Owin OAuth:使用Access Toke调用受保护的API(二)
- 在ASP.NET中基于Owin OAuth使用Client Credentials Grant授权发放Token(一)
- github asp.net一些插件封装
- asp.net jscript 一句话木马
- wamp完美支持asp
- 使用ASPxCalendar控件的时间格式注…
- ASP.NET中的Bind和Eval的区别详解