实战使用

前言:Spring(上)——AOP

测试直接在开源框架,jeesite上进行
导入依赖:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-aop</artifactId>
  4. </dependency>

切面类:

  1. package com.jeesite.modules.test.service;
  2. import org.aspectj.lang.JoinPoint;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.*;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.stereotype.Component;
  8. import java.util.Arrays;
  9. //表明当前类为切面类
  10. @Aspect
  11. //将当前类放到Spring容器中
  12. @Component
  13. public class AopTest {
  14. private static final Logger log = LoggerFactory.getLogger(AopTest.class);
  15. /*
  16. 后置切入测试
  17. */
  18. //设置要切入的点
  19. //PointCut表达式
  20. @Pointcut("execution(public * com.jeesite.modules.sys.service.support.LogServiceSupport.insertLog(..))")
  21. private void newController1() {
  22. //PointCut签名方法,没有实际作用,只是用来标记一个Pointcut,作为切入点的标记
  23. }
  24. //@After表示在目标方法之后执行下面的方法(afterController())
  25. @After("newController1()")
  26. private void afterController(JoinPoint joinPoint) {
  27. Object[] args = joinPoint.getArgs();
  28. //打印被切方法形参
  29. log.info("insertLog:{}",Arrays.toString(args));
  30. }
  31. @Pointcut("execution(public * com.jeesite.modules.sys.web.user.UserController.info(..))")
  32. private void newController2() {
  33. }
  34. /*
  35. 环绕切入测试
  36. */
  37. @Around(value = "newController2()", argNames = "pjp")
  38. private String aroundController(ProceedingJoinPoint pjp) {
  39. // try {
  40. // //proceed()方法表示执行目标方法,如果不使用proceed(),就不会执行目标方法,只会执行此方法(aroundController()),可以实现目标方法被替换的效果
  41. // pjp.proceed();
  42. // } catch (Throwable e) {
  43. // e.printStackTrace();
  44. // }
  45. // User user = new User();
  46. // user.setUserName("ahzoo");
  47. // try {
  48. //使用proceed(),可以用数组形式,传递参数给目标方法,参数个数需与目标方法形参个数一致
  49. // pjp.proceed(new Object[]{user,"",null});
  50. // } catch (Throwable e) {
  51. // e.printStackTrace();
  52. // }
  53. Object[] args = pjp.getArgs();
  54. //打印被切方法形参
  55. log.info("info:{}",Arrays.toString(args));
  56. //替换目标方法return语句
  57. return "modules/sys/user/userSelect";
  58. }
  59. /*
  60. 批量(前置)切入测试
  61. */
  62. @Pointcut("execution(public String com.jeesite.modules.sys.web.LoginController.switchSkin(..))")
  63. public void newController12() {
  64. }
  65. //可以一次对多个切面进行切入
  66. @Before("newController12() || newController1()")
  67. public void beforeController1(JoinPoint joinPoint) {
  68. log.info("测试切入");
  69. }
  70. }

Snipaste_2021-12-23_14-40-31.png

目标被切方法1(后置切入):

  1. @Transactional(readOnly=false)//, propagation=Propagation.NOT_SUPPORTED)
  2. public void insertLog(Log entity) {
  3. dao.insert(entity);
  4. }

测试图:
Snipaste_2021-12-23_14-17-36.png
Snipaste_2021-12-23_14-19-39.png
目标被切方法2(环绕切入):

  1. @RequiresPermissions("user")
  2. @RequestMapping(value = "info")
  3. public String info(User user, String op, Model model) {
  4. if (StringUtils.isBlank(op)){
  5. op = "base";
  6. }
  7. model.addAttribute("op", op);
  8. model.addAttribute("user", UserUtils.getUser());
  9. //为了显示环绕通知效果,加了这段打印代码
  10. logger.info("userInfo:{}","here");
  11. return "modules/sys/user/userInfo";
  12. }

测试图:
Snipaste_2021-12-23_14-19-04.png
Snipaste_2021-12-23_14-19-23.png

批量切入测试(前置切入):
image.png

表达式优化

优化前

  1. @Before("execution(* aa.*.*(..))")
  2. public void begin() {
  3. System.out.println("开始事务");
  4. }
  5. @After("execution(* aa.*.*(..))")
  6. public void close() {
  7. System.out.println("关闭事务");
  8. }

优化后:
优化后就只需要写一次切面表达式就行了

  1. @Pointcut("execution(* aa.*.*(..))")
  2. public void pt() {
  3. }
  4. @Before("pt()")
  5. public void begin() {
  6. System.out.println("开始事务");
  7. }
  8. @After("pt()")
  9. public void close() {
  10. System.out.println("关闭事务");
  11. }

后记

实测无法切入 子类重写父类的方法,及 通过this调用的方法