Springboot系列(十五):基于AOP实现自定义注解,简单demo演示(实战篇一)

887 阅读7分钟

👨‍🎓作者:bug菌
✏️博客:CSDN掘金infoQ51CTO
🎉简介:CSDN博客专家,C站历届博客之星Top50,掘金/InfoQ/51CTO等社区优质创作者,全网合计8w粉+,对一切技术感兴趣,重心偏Java方向;硬核公众号「 猿圈奇妙屋」,欢迎小伙伴们的加入,一起秃头,一起变强。
..
✍️温馨提醒:本文字数:1999字, 阅读完需:约 5 分钟

       嗨,家人们,我是bug菌呀,我又来啦。今天我们来聊点什么咧,OK,接着为大家更《springboot零基础入门教学》系列文章吧。希望能帮助更多的初学者们快速入门!

       小伙伴们在批阅文章的过程中如果觉得文章对您有一丝丝帮助,还请别吝啬您手里的赞呀,大胆的把文章点亮👍吧,您的点赞三连(收藏⭐+关注👨‍🎓+留言📃)就是对bug菌我创作道路上最好的鼓励与支持😘。时光不弃🏃🏻‍♀️,创作不停💕,加油☘️

一、前言🔥

环境说明:Windows10 + Idea2021.3.2 + Jdk1.8 + SpringBoot 2.3.1.RELEASE

       在一期中,我们是重点介绍了AOP的概念及一些相关知识点,如果还有小伙伴是不太清楚的,那么不要急,通过这一期的教学内容,你就会对它有一些深入的认知了,毕竟都是纯概念的东西,让未接触或者接触过一点点的小伙伴完全吸收,肯定是很困难很困难的事情。

       这一期我们将迎来实战练习,手把手带着大家怎么在项目中集成AOP并且简单使用它,后一期我将真正带着大家 如何使用AOP实现自定义注解的方式记录接口日志 业务。好吧?咱们一下不能就注解上手业务相关的代码练习,这样容易噎着。

       言归正传,我这就开始动手进行实战教学吧!大家请看下面~

二、AOP使用

1、自定义注解类实现:

package com.example.demo.annotation;

import com.example.demo.enums.LogTypeEnum;
import java.lang.annotation.*;


/**
 * 自定义注解类  @UseAop
 *
 * @Author luoYong
 * @version 1.0
 * @Date 2022-01-20 17:29        
 */
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD表示注解作用范围在方法上;具体使用可以对照下边拓展
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface UseAop {
   
}

拓展一下:

@Target注解的作用目标有以下几种:(即描述的注解的使用范围)

  •  @Target(ElementType.TYPE)  //用于接口、类、枚举、注解
  •  @Target(ElementType.FIELD)  //字段、枚举的常量
  •  @Target(ElementType.METHOD)  //方法
  •  @Target(ElementType.PARAMETER)  //方法的参数
  •  @Target(ElementType.CONSTRUCTOR)  //构造函数
  •  @Target(ElementType.LOCAL_VARIABLE)  //局部变量
  •  @Target(ElementType.ANNOTATION_TYPE)  //注解
  •  @Target(ElementType.PACKAGE)  //包

       自定义注解已经定义好了,接下来我们还要再定义一个切面类。

2、切面类实现:

package com.example.demo.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 作用是把当前类标识为一个切面供容器读取
 *
 * @author luoYong
 * @version 1.0
 * @date 2022/1/24 15:32
 */
@Aspect
@Component
public class UseAopAspect {

    /**
     * 定义切点 @Pointcut;在注解的位置切入代码
     * 
     * @annotation 表示标注了某个注解的所有方法
     * 值填你自定义注解的项目目录
     */
    @Pointcut("@annotation( com.example.demo.annotation.UseAop)")
    public void printWord() {

    }   
   /**
     * 标识一个前置增强方法,相当于BeforeAdvice的功能
     */
    @Before("printWord()")
    public void beforeAdvice() {
        System.out.println("---执行3:@Before---");
    }

    /**
     * final增强,不管是抛出异常或者正常退出都会执行
     */
    @After("printWord()")
    public void afterAdvice() {
        System.out.println("---执行4:@After---");
    }

    /**
     * 在目标方法成功执行之后调用通知
     */
    @AfterReturning("printWord()")
    public void afterReturningAdvice() {
        System.out.println("---执行5:@AfterReturning---");
    }

    /**
     * 在目标方法抛出异常后调用通知。
     */
    @AfterThrowing("printWord()")
    public void afterAdviceThrowingAdvice() {
        System.out.println("---执行6:@AfterThrowing---");
    }

    /**
     * 环绕增强,相当于MethodInterceptor
     */
    @Around("printWord()")
    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("---执行1:@Around---");
        try {
            Object result = proceedingJoinPoint.proceed();
            //注意,如果不把结果return,则接口无返回值!
            return result;
        } catch (Throwable t) {
            t.printStackTrace();
        }
        System.out.println("---执行2:@Around:异常报错---");
        return new Object();
    }
}

       以上切面就创建好了,那接下来就到了重要环节了,我们先随便定义一个接口方法,然后用我们刚定义好的注解进行修饰,然后看看控制台到底会发生什么事情?

3、添加一个控制器

       添加一个控制器,进行测试访问。这里咱们就以UserController为例吧。这个你们就随意创建一个,或者直接写个空方法或者返回个字符串都行。

       比如我就是直接拿现成的查询用户列表接口来做个测试啊。请看如下:

package com.example.demo.controller;

import com.example.demo.annotation.UseAop;
import com.example.demo.entity.UserEntity;
import com.example.demo.vo.UserInfoVo;
import com.example.demo.dao.UserMapper;
import com.example.demo.model.QueryUserInfoModel;
import com.example.demo.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

/**
 * 用户管理分发器
 */
@RestController@RequestMapping("/user")
@Api(tags = "用户管理模块",description = "用户管理模块")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 不分页查询db1所有用户信息
     */
    @UseAop //切入
    @GetMapping("/get-users1")
    @ApiOperation(value = "不分页查询db1所有用户信息",notes = "不分页查询db1所有用户信息")
    public List<UserEntity> getUserList() {
        return userService.getUsers();
    }
}

       你们可以看到,我直接在我定义的getUserList() 方法上加了我们刚才自定义的注解@UseAop,对吧。你们也记得把它,然后在加上自定义注解与不加上自定义注解,二者进行一下对比,看看是否会成功执行到切面的方法进行输出打印?让我们期待一下

  • 如下是未加上自定义注解时控制台打印的截图:

  • 如下是已加上自定义注解时控制台打印的截图:

       如上结果,你们看到了什么,切面类中的通知(advice)已经都被执行且输出打印,要注意的是,假如全部都通知,可以看到是有先后通知顺序的,但一般这五种通知类型不会同时都放在一起使用的,常见的玩法在项目中就是使用@AfterReturning的 比较多,比如记录接口日志的具体调用情况(比如:获取调用人账户、调用时接口参数、调用者ip、调用时间、调用返回数据、调用操作类型等),就是在目标方法成功执行后调用通知进行获取,这操作一般比较多。还有就是权限校验,那就是在调用目标方法前进行切入,然后获取调用者账户信息再进行权限校验判断该用户是否有权限进行接口访问等。

       基本就是这些常见的玩法啦,还有更多的咱们日后再讲,或者大家有啥更好的玩法也可以在下方评论区告诉我,互相学习,一起进步。

... ...

       OK,以上就是这期所有的内容啦,如果有任何问题欢迎评论区批评指正,咱们下期见。

三、往期热门推荐

文末🔥

如果还想要学习更多,小伙伴们可关注bug菌专门为大家创建的专栏《springboot零基础入门教学》,从无到有,从零到一!希望能帮助到更多小伙伴们。

我是bug菌,一名想走👣出大山改变命运的程序猿。接下来的路还很长,都等待着我们去突破、去挑战。来吧,小伙伴们,我们一起加油!未来皆可期,fighting!

感谢认真读完我博客的铁子萌,在这里呢送给大家一句话,不管你是在职还是在读,绝对终身受用。
时刻警醒自己:
抱怨没有用,一切靠自己;
想要过更好的生活,那就要逼着自己变的更强,生活加油!!!