在 SpringBoot 中引入 aop 切面编程

目录

一:AOP 切面的快速引用

1. 引入依赖:

2. 定义 AOP 切面类(建议新建 aop 包,不要忘了加上 @Aspect、@Component 注解):

3. 编写核心业务代码:

二:AOP 切面的环绕通知

 三:通知方法传参


一:AOP 切面的快速引用

1. 引入依赖:

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

2. 定义 AOP 切面类(建议新建 aop 包,不要忘了加上 @Aspect、@Component 注解):

package com.example.springbootaop.aop;

import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

   /**
    * 日志打印
    */
   private Logger logger = LoggerFactory.getLogger(this.getClass());

   /**
    * 使用Pointcut给这个方法定义切点,即UserService中全部方法均为切点。<br>
    * 这里在这个log方法上面定义切点,然后就只需在下面的Before、After等等注解中填写这个切点方法"log()"即可设置好各个通知的切入位置。
    * 其中:
    * <ul>
    *     <li>execution:代表方法被执行时触发</li>
    *     <li>*:代表任意返回值的方法</li>
    *     <li>com.example.springbootaop.service.impl.UserServiceImpl:这个类的全限定名</li>
    *     <li>(..):表示任意的参数</li>
    * </ul>
    */
   @Pointcut("execution(* com.example.springbootaop.service.impl.UserServiceImpl.*(..))")
   public void log() {

   }

   /**
    * 前置通知:在被代理方法之前调用
    */
   @Before("log()")
   public void doBefore() {
      logger.warn("调用方法之前:");
      logger.warn("接收到请求!");
   }

   /**
    * 后置通知:在被代理方法之后调用
    */
   @After("log()")
   public void doAfter() {
      logger.warn("调用方法之后:");
      logger.warn("打印请求内容完成!");
   }

   /**
    * 返回通知:被代理方法正常返回之后调用
    */
   @AfterReturning("log()")
   public void doReturning() {
      logger.warn("方法正常返回之后:");
      logger.warn("完成返回内容!");
   }

   /**
    * 异常通知:被代理方法抛出异常时调用
    */
   @AfterThrowing("log()")
   public void doThrowing() {
      logger.error("方法抛出异常!");
   }

}

引入代码后,将 log 方法的 @Pointcut 注解中的参数:

com.example.springbootaop.service.impl.UserServiceImpl

改为自己的 Impl 包的全限定名

3. 编写核心业务代码:

Controller:

@GetMapping("/testAOP")
public void testAOPController() {
    log.info("执行业务代码");
    userService.testAOPService();
    log.info("业务代码执行完毕");
}

Service:

/**
 * 测试 AOP 引入
 */
void testAOPService();

ServiceImpl:

@Override
public void testAOPService() {
    log.info("核心业务代码......");
}

调用 Controller 的接口后的效果:

 只有框中的代码是我们在 业务代码编写的,其余都是经过了 AOP 切面添加。

二:AOP 切面的环绕通知

在 aop 切面类中加入环绕通知的方法:

aop 类:

/**
 * 环绕通知
 */
@Around("log()")
public void around(ProceedingJoinPoint joinPoint) {
   logger.warn("执行环绕通知之前:");
   try {
      joinPoint.proceed();
   } catch (Throwable e) {
      e.printStackTrace();
   }
   logger.warn("执行环绕通知之后");
}

通知方法中有一个 ProceedingJoinPoint 类型参数,通过其  proceed 方法来调用原方法。需要注意的是环绕通知是会覆盖原方法逻辑的,如果上面代码不执行joinPoint.proceed();这一句,就不会执行原被织入方法。因此环绕通知一定要调用参数的 proceed 方法,这是通过反射实现对被织入方法调用。

再次测试如下:

已经在使用已有的原通知前引入了环绕通知引入了

 三:通知方法传参

上面每个通知方法是没有参数的。下面我们实现在前置通知方法中植入的参数

    /**
     * 前置通知:在被代理方法之前调用
     */
    @Before("log() && args(num)")
    public void doBefore(Integer num) {
        logger.warn("调用方法之前:");
        logger.info("引入的参数 num:" + num);
        logger.warn("接收到请求!");
    }

可见在注解后面加一个 args 选项,里面写参数名即可。

需要注意的是,通知方法的参数必须和被植入方法参数一一对应例如:

业务代码的改动:

Controller:

    @GetMapping("/testAOP")
    public void testAOPController() {
        log.info("执行业务代码");
        userService.testAOPService(1);
        log.info("业务代码执行完毕");
    }

Service:

    /**
     * 测试 AOP 引入
     */
    void testAOPService(int num);

ServiceImpl:

    @Override
    public void testAOPService(int num) {
        log.info("核心业务代码......");
    }

再次测试结果:

 当然,传入 aop 方法中的参数也可以是非基本数据类型,只需要把传入参数的类型改一下就好

转载来自:

https://juejin.cn/post/6999570632409088008

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值