心灵鸡汤:

加载中...

spring实现切面编程

Spring两大特性

  • IOC(控制反转)

    IOC:通俗点来讲,就是把对象的创建交给Spring容器来管理,不用我们手动new

  • AOP(面向切面编程)

    AOP:定义一个切面,在切面中执行特定代码,实现代码增强,常用于日志打印,异常处理,性能耗时计算,事务处理,安全验证等等,

用AOP和不用AOP做日志记录的区别

  • 不用AOP:

    每个方法都要写记录日志的代码,代码多,工作量大

  • 使用AOP:

    日志统一交给某个类(切面配置类)来记录,这样做的好处是业务代码简洁了,也能达到一定的解耦等等

AOP实战之旅(基于注解)

  • 实战环境:jdk8、SpringBoot2.4.3、maven3.6。
  • @Pointcut: 切点。
  • @Before: 切面方法执行之前执行。
  • @After: 切面方法执行之后执行 。
  • @AfterRunning: 切面方法成功返回结果之后执行
  • @AfterThrowing: 切面方法抛出异常后执行

1、SpringBoot项目搭建,并加入AOP依赖

 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2、创建切面类SystemLogAspect

@Aspect  //标识为一个切面类
@Component   //交给Spring管理
public class SystemLogAspect {

//@Pointcut("@annotation(com.demo.aop.joggle.SystemLogInterface)")  //应用在有@SystemLogInterface注解的方法上
  public void controllerAspect(){
    
    System.out.println("我是切点");
}

@Before("controllerAspect()")
  public void doBefore(JoinPoint joinPoint) {

    // 线程绑定变量(该数据只有当前请求的线程可见)
    Date beginTime = new Date();
    System.out.println("方法执行前通知");
    //doSomething
}

  @AfterReturning("controllerAspect()")
  public void after(JoinPoint joinPoint) {

    System.out.println("方法返回结果后执行");
    //doSomething
}

  @AfterThrowing("controllerAspect()")
  public void afterThrow(JoinPoint joinPoint){

    System.out.println("方法发生异常后执行");
    //doSomething
}
}

3、创建自定义注解SystemLogInterface

/**
 * @description:切面注解
  * @author: Mosey
 * @time: 2021/3/6 14:50
 */ 
@Target(ElementType.METHOD)//作用于参数或方法上 
@Retention(RetentionPolicy.RUNTIME)
@Documented   
public @interface SystemLogInterface {

}

4、创建TestController,并在test方法处使用自定义的SystemLogInterface注解

@RequestMapping(value = "/test")
@Slf4j 
@RestController   
public class TestController {

    @SystemLogInterface
    @GetMapping(value = "/aop")
    public String test(){
    
      System.out.println("方法正在执行中。。。");
      return "访问成功";
    }

}

5、运行项目。访问localhost:8080/test/aop会打印出下面的结果

方法执行前通知

方法正在执行中。。。
方法返回结果后执行

!>注意:如果方法运行时发生异常,会进入到@AfterThrowing中,如果我们有在test()方法中捕获异常,则不会进入@AfterThrowing。

AOP实战之旅(不基于注解)

  • 上面的切面类SystemLogAspect的切点用到的是@Pointcut("@annotation(com.demo.aop.joggle.SystemLogInterface)")基于注解实现AOP的。

  • 其实我们也可以用@Pointcut("execution(* com.demo.aop.controller..test())")来进行切点。

  • execution(* com.demo.aop.controller..test())意思是:com.demo.aop.controller包下的所有类的test方法(),括号里边的..表示任何参数。

  • PS:切点换成execution表达式后,要把controller层的@SystemLogInterface注解注释掉。

  • 运行结果和上面的一样

    方法执行前通知

    方法正在执行中。。。
    方法返回结果后执行
    

execution表达式

更多有关于execution表达式的,可以看下面的截图,execution也可以用连接符&& || 和!等匹配多个表达式,具体问题具体分析

execution表达式.png

补充

1.当@Before@After@Around@AfterReturning@AfterThrowing同时使用并切点相同时

  • @Around中没有调用pjp.proceed()方法时,不执行切点对应的目标方法

  • 如果有调用pjp.proceed()方法时,开始执行切点对应的目标方法(无异常情况),顺序:@Around =》@Before =》pjp.proceed()执行切点方法 =》@AfterReturning =》@After

  • 如果有调用pjp.proceed()方法时,开始执行切点对应的目标方法(有异常情况),顺序:@Around =》@Before =》目标方法发生异常,不返回数据 =》@AfterThrowing拦截 =》@After

2.如果有多个切面,使用@Order(Integer)注解多个切面,Integer越小,优先级越高。

posted @ 2025-03-20 15:22  Mosey  阅读(56)  评论(0)    收藏  举报
TOP