Spring Boot整合AOP

前期回顾:
创建Spring Boot项目
Spring Boot项目基础配置
Spring Boot上传文件
Spring Boot全局异常处理、全局数据、参数预处理
Spring Boot自定义拦截器
Spring Boot整合Servlet、Filter和Listener

AOP作为Spring的一个重点同时也是一个难点,其实我整的也不是很明白,哈哈哈。
进入正题,AOP官方的解释是:面向切面编程
在AOP中有几个概念需要知道:

  • Joinpoint:连接点,类里面被增强的方法称为连接点
  • Pointcut: 切入点,对增强的方法进行拦截视为切入点
  • Advice:通知,在切入点切入需要干的事情,可以分为前置通知、后置通知、异常通知、最终通知和环绕通知
  • Aspect:切面,切入点和通知组合为一个切面
  • Target:目标对象,上述点整合为一个目标

下面来举例说明:
程序猿A下班时被同事约饭,到达饭店时想起了家有母老虎必须通知啊,也是拿起手机拿起电话一顿解释。接下来就是愉快的喝酒吃饭时间了,饭吃完的他为了等下到家不跪键盘,于是问候下母老虎是否需要带啥吃的给她,(此处有惊喜),到家后通知朋友安全到家。

将A作为目标对象,和同事约饭作为连接点,那么向家里解释就是第一切入点,为前置通知,而吃完饭后的“问候”视为第二切入点,为后置通知,到家后通知朋友安全到家可以当作为最终通知。

接下来通过具体代码来实现:

  • maven依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • 定义AOP目标
import com.lei.tang.demo.service.people.ApeService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class ApeSpect {

    @Autowired
    private ApeService apeService;

    @Pointcut(value = "execution(* com.demo.service.people.ApeServiceImpl.haveMeal(..))")
    public void logPointcut() {

    }

    @Before(value = "logPointcut()")
    public void before(JoinPoint joinPoint) {
        //获取request
        //HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
        // .getRequest();
        //后去请求ip request.getRemoteAddr()
        apeService.call("打电话告知家里今天不回去吃饭了");
    }

    @After(value = "logPointcut()")
    public void after(JoinPoint joinPoint) {
        apeService.call("告知饭已吃完");
    }
    
    @AfterReturning(value = "logPointcut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        apeService.call("告知朋友顺利到家");
    }

    @AfterThrowing(value = "logPointcut()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        apeService.call("通知同事他老婆来医院");
    }
}

代码解释:
通过@Aspect注解将ApeSpect定义为一个AOP目标对象,需注意的是记得加上@Component注解将它交由Spring管理哦。@Pointcut定义了com.demo.service.people包下的ApeServiceImpl类中的haveMeal方法为连接点,也就是下面切入点能切入的地方,@Before执行方法前执行,@After方法执行完成执行,@AfterReturning正常返回后执行,@AfterThrowing抛出异常后执行。

  • service实现
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service("apeService")
public class ApeServiceImpl implements ApeService {

    @Override
    public String haveMeal(Boolean status) throws InterruptedException {
        log.info("吃饭");
        if (!status) {
            throw new RuntimeException("同事醉酒进医院");
        }
        return "吃饭";
    }

    @Override
    public void call(String msg) {
        log.info("电话====》{}", msg);
    }
}
  • 来个Controller测试一波
import com.lei.tang.demo.service.people.ApeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/ape")
public class ApeController {

    @Autowired
    ApeService apeService;

	/**
     * true代表正常吃饭,false表示有人醉酒
     *
     * @param status
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/haveMeal")
    public String haveMeal(@RequestParam Boolean status) throws InterruptedException {
        return apeService.haveMeal(status);
    }
}

来个正常的:http://localhost:8080/demo/ape/haveMeal?status=true
打印结果:
测试结果
那么不正常的呢?前面说的惊喜呢?调用:http://localhost:8080/demo/ape/haveMeal?status=false
打印结果:
测试结果
有没有发现惊喜呢,因为同事醉酒被我送去了医院,所以我没有回家。也就是说当执行方法的过程中抛出了异常,那么将不会进入@AfterReturning注解的方法,则会进入@AfterThrowing方法。

上面一直没有提到环绕通知,最后就来演示下环绕通知,将上面的AOP类改为下面的代码:

import com.lei.tang.demo.service.people.ApeService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class ApeSpect {

    @Autowired
    private ApeService apeService;

    /**
     * 定义切入点
     */
    @Pointcut(value = "execution(* com.lei.tang.demo.service.people.ApeServiceImpl.haveMeal(..))")
    public void logPointcut() {

    }
    
    @AfterThrowing(value = "logPointcut()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        apeService.call("通知同事他老婆来医院");
    }

    @Around(value = "logPointcut()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        apeService.call("打电话告知家里今天不回去吃饭了");
        proceedingJoinPoint.proceed();
        apeService.call("告知饭已吃完");
    }
}

@Around是@Before与@After的组合,proceedingJoinPoint.proceed()方法是执行真正需要执行的方法。
测试调用与上面一致,可以自己去试试控制台打印的结果哦。

如有不到之处,欢迎各位留言指正,不慎感激。
更多文章:
点击跳转CSDN博客
点击跳转简书博客
微信公众号:代码小搬运
微信扫码关注代码小搬运公众号

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值