经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
浅谈@Aspect@Order各个通知的执行顺序
来源:jb51  时间:2022/2/14 13:36:07  对本文有异议

@Aspect@Order各个通知的执行顺序

两个切面类:【记录日志】和【判断参数】,分别对应顺序 @Order(0) 和@Order(1) 。

本文只是将重点说下 执行顺序 这么回事哈哈哈

代码

【业务类】

  1. /**
  2. * 登录控制器
  3. */
  4. @Controller
  5. public class LoginController {
  6. //向外面抛出异常
  7. public void loginWithThrow(String username, String password) throws Exception {
  8. if (username == null || password == null) {
  9. throw new Exception("登录信息不可为空啊");
  10. }
  11. System.out.println("LoginController#login...");
  12. }
  13. //抛出异常自己捕获的情况
  14. public void loginWithTryCatch(String username, String password) {
  15. try{
  16. if (username == null || password == null) {
  17. throw new Exception("登录信息不可为空啊");
  18. }
  19. System.out.println("LoginController#login...");
  20. }catch (Exception e){
  21. e.printStackTrace();
  22. }
  23. }
  24. }

【切面类】

  1. /**
  2. * 输出日志注解
  3. */
  4. @Order(0)
  5. @Aspect
  6. @Component
  7. public class LogAspect {
  8. //抽出共通的execution用的
  9. //com.yuki.demo.aop.aspect 包或者子包下所有类的方法
  10. @Pointcut("execution(* com.yuki.demo.aop.aspect..*.*(..))")
  11. public void pointcut(){
  12. }
  13. //前置通知
  14. // @Before("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
  15. @Before("pointcut()")
  16. public void before() {
  17. System.out.println("LogAspect#before...");
  18. }
  19. //环绕通知
  20. //ProceedingJoinPoint 只有环绕通知有
  21. @Around("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
  22. public void around(ProceedingJoinPoint joinPoint) throws Throwable {
  23. System.out.println("LogAspectA#around开始...");
  24. //代理方法的执行,如果没有joinPoint.proceed() ,则前置通知@Before 不会执行,其它的通知正常
  25. joinPoint.proceed();
  26. //执行方法之后,如果joinPoint.proceed() 抛出了异常,则该句不会执行,抛出异常后直接跳出了aroud方法了
  27. System.out.println("LogAspectA#around结束...");
  28. }
  29. //后置通知(只要连接点被执行,不管是否抛出异常)
  30. @After("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
  31. public void after() {
  32. System.out.println("LogAspect#after...");
  33. }
  34. //异常通知(只有在joinPoint.proceed()方法执行向外面抛出了异常,才会执行该通知)
  35. @AfterThrowing("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
  36. public void afterThrowing() {
  37. System.out.println("LogAspect#afterThrowing...");
  38. }
  39. //正常的返回通知通知(正常结束了才会执行该通知)
  40. @AfterReturning("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
  41. public void afterReturning() {
  42. System.out.println("LogAspect#afterReturning...");
  43. }
  44. }

【切面类】

  1. /**
  2. * 判断请求参数的sign是否正确的 切面类
  3. */
  4. @Order(1)
  5. @Aspect
  6. @Component
  7. public class SignAspect {
  8. @Around("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
  9. public void around(ProceedingJoinPoint joinPoint) throws Throwable {
  10. System.out.println("SignAspect#around开始...");
  11. joinPoint.proceed();
  12. System.out.println("SignAspect#around结束...");
  13. }
  14. }

【启动配置】

省略。。。非重点

【测试类】

  1. @SpringBootTest
  2. class AopApplicationTests {
  3. @Autowired
  4. private LoginController loginController;
  5. @Test
  6. void contextLoads() {
  7. loginController.loginWithTryCatch("yuki", "1234");
  8. }
  9. }

【控制台输出】

LogAspectA#around开始...
LogAspect#before...
SignAspect#around开始...
LoginController#login...
SignAspect#around结束...
LogAspectA#around结束...
LogAspect#after...
LogAspect#afterReturning...

小结

spring AspectJ order(顺序)

  1. @Aspect
  2. @Order(2)
  3. public class HelloWorldAspectAnnotation {
  4. /**
  5. * JoinPoint接口
  6. * @param joinPoint
  7. */
  8. /*public interface JoinPoint {
  9. String toString(); //连接点所在位置的相关信息
  10. String toShortString(); //连接点所在位置的简短相关信息
  11. String toLongString(); //连接点所在位置的全部相关信息
  12. Object getThis(); //返回AOP代理对象
  13. Object getTarget(); //返回目标对象
  14. Object[] getArgs(); //返回被通知方法参数列表
  15. Signature getSignature(); //返回当前连接点签名
  16. SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置
  17. String getKind(); //连接点类型
  18. StaticPart getStaticPart(); //返回连接点静态部分
  19. }*/
  20. //定义前置通知,注意这里是sayHello2
  21. //使用@Before进行前置通知声明,其中value用于定义切入点表达式或引用命名切入点
  22. @Before(value="execution(* com.boventech..*.sayHello2(..))&& args(param)",argNames="param")
  23. public void beforeAdvice(JoinPoint joinPoint,String param) {
  24. System.out.println(1);
  25. System.out.println("=======================");
  26. System.out.println("===param:" + param);
  27. System.out.println("=======================");
  28. System.out.println(joinPoint.getArgs().length);
  29. System.out.println("=======================");
  30. System.out.println(joinPoint.toString());
  31. System.out.println("=======================");
  32. System.out.println(joinPoint.getTarget());
  33. System.out.println("=======================");
  34. System.out.println(joinPoint.getThis());
  35. System.out.println("=======================");
  36. System.out.println("===========before advice");
  37. }
  38. /*value:指定切入点表达式或命名切入点;
  39. pointcut:同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;*/
  40. @AfterReturning(value="execution(* com.boventech..*.sayHello2(..))&& args(param)",argNames="param",pointcut="execution(* com.boventech..*.sayHello2(..))&& args(param)")
  41. public void afterFinallyAdvice(JoinPoint joinPoint,String param) {
  42. System.out.println("param:"+param);
  43. System.out.println("===========");
  44. System.out.println("===========after finally advice");
  45. }
  46. }
  1. @Aspect
  2. @Order(1)
  3. public class HelloWorldAspectAnnotation2 {
  4. /**
  5. * JoinPoint接口
  6. * @param joinPoint
  7. */
  8. /*public interface JoinPoint {
  9. String toString(); //连接点所在位置的相关信息
  10. String toShortString(); //连接点所在位置的简短相关信息
  11. String toLongString(); //连接点所在位置的全部相关信息
  12. Object getThis(); //返回AOP代理对象
  13. Object getTarget(); //返回目标对象
  14. Object[] getArgs(); //返回被通知方法参数列表
  15. Signature getSignature(); //返回当前连接点签名
  16. SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置
  17. String getKind(); //连接点类型
  18. StaticPart getStaticPart(); //返回连接点静态部分
  19. }*/
  20. //定义前置通知,注意这里是sayHello2
  21. //使用@Before进行前置通知声明,其中value用于定义切入点表达式或引用命名切入点
  22. @Before(value="execution(* com.boventech..*.sayHello2(..))&& args(param)",argNames="param")
  23. public void beforeAdvice(JoinPoint joinPoint,String param) {
  24. System.out.println(2);
  25. System.out.println("=======================");
  26. }
  27. /*value:指定切入点表达式或命名切入点;
  28. pointcut:同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;*/
  29. @AfterReturning(value="execution(* com.boventech..*.sayHello2(..))&& args(param)",argNames="param",pointcut="execution(* com.boventech..*.sayHello2(..))&& args(param)")
  30. public void afterFinallyAdvice(JoinPoint joinPoint,String param) {
  31. System.out.println("order:" + 2);
  32. }
  33. }
  1. public class AopAnnotationTest {
  2. @Test
  3. public void testHelloworld() {
  4. ApplicationContext ctx = new ClassPathXmlApplicationContext("/helloWorld2.xml");
  5. IHelloWorld2Service helloworldService =ctx.getBean("helloWorld2Service", IHelloWorld2Service.class);
  6. String param = "12";
  7. helloworldService.sayHello2(param);
  8. }
  9. }
  1. <aop:aspectj-autoproxy/>
  2. <bean id="helloWorld2Service" class="com.boventech.learning.serviceImpl.HelloWorld2ServiceImpl"/>
  3. <bean id="aspect"
  4. class="com.boventech.learning.aspect.HelloWorldAspectAnnotation"/>
  5. <bean id="aspect2"
  6. class="com.boventech.learning.aspect.HelloWorldAspectAnnotation2"/>

以上为个人经验,希望能给大家一个参考,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号