SpringBoot-自定义注解AOP实现及拦截器示例

SpringBoot-自定义注解AOP实现及拦截器示例

一、四大元注解

当你在编写自定义注解时@Target、@Retention、@Documented 和 @Inherited 是四个你可能会用到的元注解,它们可以帮助你更好地定义和使用注解

1、@Target

@Target 注解用于指定注解可以应用的程序元素类型。它的值是一个 ElementType 数组,表示该注解可以应用到哪些地方,包括类、接口、方法、字段等。常用的 ElementType 类型包括:

  • ElementType.TYPE:类、接口、枚举
  • ElementType.METHOD:方法
  • ElementType.FIELD:字段
  • ElementType.PARAMETER:方法参数
  • ElementType.CONSTRUCTOR:构造方法
  • ElementType.LOCAL_VARIABLE:局部变量
  • ElementType.ANNOTATION_TYPE:注解类型
  • ElementType.PACKAGE:包

例如,如果你希望你的注解只能应用在方法上,你可以这样定义:

@Target(ElementType.METHOD)

2、@Retention

@Retention 注解用于指定注解的保留策略,即注解在编译时、运行时或者在类文件中都保留。它的值是一个 RetentionPolicy 枚举,包括:

  • RetentionPolicy.SOURCE注解仅保留在源代码中,在编译时丢弃
  • RetentionPolicy.CLASS注解保留到类文件中,在运行时丢弃(默认值)
  • RetentionPolicy.RUNTIME:注解保留到运行时,可以通过反射获取

例如,如果你希望你的注解在运行时可用,你可以这样定义:

@Retention(RetentionPolicy.RUNTIME)

3、@Documented

@Documented 注解表示该注解应该被 javadoc 工具记录,因此可以在生成的文档中看到该注解及其说明。它没有任何属性,只需将其放在注解声明之前即可。

例如:

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {// 注解的定义
}

在生成的文档中,你将能够看到使用了 MyAnnotation 的地方以及相关说明。

4、@Inherited

@Inherited 注解表示该注解可以被子类继承。当一个类使用了被 @Inherited 注解的注解时,其子类也会继承该注解。需要注意的是,@Inherited 只对类的继承有效,对接口、方法、字段等不起作用。

例如:

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {// 注解的定义
}

在这个例子中,如果一个父类被 @MyAnnotation 注解修饰,在子类中同样会被继承。

这些元注解可以帮助你更灵活地定义和使用自定义注解,根据具体需求选择合适的元注解来控制注解的行为。

二、自定义注解实现

1、创建注解

自定义注解:CustomAnnotation

package com.kdz.demo.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {String value1() default "";String value2() default "";
}

2、AOP实现

创建AOP切面类CustomAspect,指定自定义注解为切入点

指定自定义注解为切入点,定义了切入点表达式和前后通知

package com.kdz.demo.Aspect;import com.kdz.demo.annotation.CustomAnnotation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
public class CustomAspect {private static final Logger logger = LoggerFactory.getLogger(CustomAspect.class);//指定自定义注解为切入点@Pointcut("@annotation(customAnnotation)")public void customAnnotationPointcut(CustomAnnotation customAnnotation) {}@Before("@annotation(customAnnotation)")public void beforeAdvice(CustomAnnotation customAnnotation) {System.out.println("Before advice: " + customAnnotation.value1() + " - " + customAnnotation.value2());}@After("@annotation(customAnnotation)")public void afterAdvice(CustomAnnotation customAnnotation) {System.out.println("After advice: " + customAnnotation.value1() + " - " + customAnnotation.value2());}@Around("@annotation(customAnnotation)")public Object aroundAdvice(ProceedingJoinPoint joinPoint, CustomAnnotation customAnnotation) throws Throwable {long startTime = System.currentTimeMillis();Object result = joinPoint.proceed();long endTime = System.currentTimeMillis();long executionTime = endTime - startTime;logger.info("Method: " + joinPoint.getSignature().getName());logger.info("Execution Time: " + executionTime + "ms");Object[] args = joinPoint.getArgs();for (int i = 0; i < args.length; i++) {logger.info("Parameter " + (i + 1) + ": " + args[i]);}logger.info("Annotation: " + customAnnotation.value1() + " - " + customAnnotation.value2());return result;}
}

在这个更新后的切面类中,我们使用了@Around通知来围绕目标方法的执行。在方法执行前记录了开始时间,在方法执行后记录了结束时间,并计算了方法的执行时间。我们还获取了方法的参数,并将这些信息都记录在日志中。

3、使用自定义注解

package com.kdz.demo.service;import com.kdz.demo.annotation.CustomAnnotation;
import org.springframework.stereotype.Service;@Service
public class DemoService {@CustomAnnotation(value1 = "湖人总冠军", value2 = "666LBJ666")public void doSomething() {System.out.println("Doing something...");}
}

4、测试

在这里插入图片描述

package com.kdz.demo;import com.kdz.demo.service.DemoService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class UserDefinedAnnotationApplicationTests {@AutowiredDemoService demoService;@Testvoid contextLoads() {demoService.doSomething();}
}

在这里插入图片描述

三、配合MVC拦截器判断是否携带token

1、创建注解

自定义注解:TokenRequired

package com.kdz.demo.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TokenRequired {
}

2、AOP实现

创建AOP切面类TokenRequiredAspect,指定自定义注解为切入点

指定自定义注解为切入点,定义了切入点表达式前置通知

package com.kdz.demo.Aspect;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;@Aspect
@Component
public class TokenRequiredAspect {private static final Logger logger = LoggerFactory.getLogger(TokenRequiredAspect.class);@Before("@annotation(com.kdz.demo.annotation.TokenRequired)")public void beforeTokenRequiredMethod() {logger.info("Executing method with TokenRequired annotation...");}
}

3、使用自定义注解

package com.kdz.demo.controller;import com.kdz.demo.annotation.TokenRequired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {@GetMapping("/hello")@TokenRequiredpublic String hello() {return "Hello, World!";}
}

4、配置启动类

package com.kdz.demo;import com.kdz.demo.config.AuthenticationHandlerInterceptor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@SpringBootApplication
public class UserDefinedAnnotationApplication implements WebMvcConfigurer {public static void main(String[] args) {SpringApplication.run(UserDefinedAnnotationApplication.class, args);}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new AuthenticationHandlerInterceptor());}}

​ 我们的应用程序的启动类 UserDefinedAnnotationApplication 上添加了 @SpringBootApplication 注解,并实现了 WebMvcConfigurer 接口,并重写了 addInterceptors 方法,在这个方法中注册了我们的拦截器 AuthenticationHandlerInterceptor。这样,拦截器就会被正确地加载和注册到应用程序中。

5、拦截器实现

拦截器判断是否使用注解及是否携带特定token

package com.kdz.demo.config;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import com.kdz.demo.annotation.TokenRequired;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;@Component
public class AuthenticationHandlerInterceptor implements HandlerInterceptor {private static final Logger logger = LoggerFactory.getLogger(AuthenticationHandlerInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {logger.debug("进入拦截器, URL: {}", request.getServletPath());if (!(handler instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) handler;// 检查请求的方法是否添加了 TokenRequired 注解if (!handlerMethod.hasMethodAnnotation(TokenRequired.class)) {logger.debug("接口未添加 TokenRequired 注解,直接放行");return true;}// 获取请求中的 tokenString token = request.getHeader("Authorization");// 进行 token 验证if (token != null && token.equals("Bearer LBJ666")) {return true; // Token 验证通过,允许请求通过} else {// Token 验证失败,返回未授权错误response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");return false;}}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

6、测试效果

1)未使用自定义注解TokenRequired

在这里插入图片描述

在这里插入图片描述

2)使用注解

使用正确token

在这里插入图片描述

在这里插入图片描述

使用错误token

在这里插入图片描述

在这里插入图片描述
SpringBoot-自定义注解AOP实现及拦截器示例 到此完结,笔者归纳、创作不易,大佬们给个3连再起飞吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/587.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【科研入门】评价指标AUC原理及实践

评价指标AUC原理及实践 目录 评价指标AUC原理及实践一、二分类评估指标1.1 混淆矩阵1.2 准确率 Accuracy定义公式局限性 1.3 精确率 Precision 和 召回率 Recall定义公式 1.4 阈值定义阈值的调整 1.5 ROC与AUC引入定义公式理解AUC算法 一、二分类评估指标 1.1 混淆矩阵 对于二…

【muzzik 分享】关于 MKFramework 的设计想法

MKFramework是我个人维护持续了几年的项目&#xff08;虽然公开只有一年左右&#xff09;&#xff0c;最开始由于自己从事QP类游戏开发&#xff0c;我很喜欢MVVM&#xff0c;于是想把他做成 MVVM 框架&#xff0c;在论坛第一个 MVVM 框架出来的时候&#xff0c;我的框架已经快完…

电机控制专题(二)——Sensorless之扩展反电动势EEMF

文章目录 电机控制专题(二)——Sensorless之扩展反电动势EEMF前言理论推导仿真验证总结参考文献 电机控制专题(二)——Sensorless之扩展反电动势EEMF 前言 总结下电机控制中的扩展反电动势模型。 纯小白&#xff0c;如有不当&#xff0c;轻喷&#xff0c;还请指出。 在得出E…

synchronized锁升级原理

锁升级过程 jdk1.6之后的优化 synchronized锁有四种状态&#xff0c;无锁&#xff0c;偏向锁&#xff0c;轻量级锁&#xff0c;重量级锁&#xff0c;这几个状态会随着竞争状态逐渐升级&#xff0c;锁可以升级但不能降级&#xff0c;但是偏向锁状态可以被重置为无锁状态。 1、偏…

深入挖掘C语言 ---- 文件操作

目录 1. 文件的打开和关闭1.1 流和标准流1.1.1流1.1.2标准流 1.2 文件指针1.3 文件的打开和关闭 2. 顺序读写3. 随机读写3.1 fseek3.2 ftell3.3 rewind 4. 读取结束判定 正文开始 1. 文件的打开和关闭 1.1 流和标准流 1.1.1流 我们程序的数据需要输出到各种外部设备, 也需要…

CentOS7升级openssl

文章目录 一 系统环境二 操作步骤三 版本检查 一 系统环境 公司服务器等保要求&#xff0c;修复openssl的高危漏洞。 本机使用centos7.9系统&#xff0c;openssl版本是1.0.2k&#xff0c;计划升级到1.1.1q 在执行下列操作前&#xff0c;务必要打快照做好备份&#xff0c;以防升…

浮点数随机生成器

浅做了一个数值模拟器&#xff0c;支持自定义多路数据模拟。数据源支持浮点型、整形等多种类型&#xff0c;通讯支持网口和串口&#xff0c;支持指定协议。简略效果大概如下&#xff0c;后续可能会考虑开源~ [code] 浮点数生成器 #include <iostream> #include <ra…

Scala 04 —— 函数式编程底层逻辑

函数式编程 底层逻辑 该文章来自2023/1/14的清华大学交叉信息学院助理教授——袁洋演讲。 文章目录 函数式编程 底层逻辑函数式编程假如...副作用是必须的&#xff1f;函数的定义函数是数据的函数&#xff0c;不是数字的函数如何把业务逻辑做成纯函数式&#xff1f;函数式编程…

【python】直接在python3下安装 jupyter notebook,以及处理安装报错,启动不了问题

目录 问题&#xff1a; 1 先做准备&#xff0c;查看环境 1.1 先看python3 和pip &#xff0c;以及查看是否有 juypter 1.2 开始安装 1.3 安装完成后得到警告和报错 2 处理安装的报错问题 2.1 网上有说是因为 pip 自身需要更新&#xff0c;更新之 2.1.1 更新pip 2.1.…

Redis搭建主从

Redis搭建主从: 1:拉取Redis镜像 docker pull redis2:创建主从对应的目录结构 3:对redis6379.log,redis6380.log,redis6381.log进行授权 chmod 777 redis6379.log chmod 777 redis6380.log chmod 777 redis6381.log4:修改主(master)的配置文件 5:创建主(master) redis_6379 …

docker部署java项目,如何docker-compose内的jdk版本与本地版本保持一致

目录结构 /var └── data├── docker-compose.yml └── docker├── Dockerfile└── jdk-8u401-linux-x64.tar.gzdockerfile文件 FROM ubuntu:latest# 拷贝本地服务器上的 JDK 安装包到 Docker 镜像中 COPY jdk-8u401-linux-x64.tar.gz /jdk-8u401-linux-x64.tar.g…

基于弹簧鞘复合纱和迁移学习算法的可穿戴人体重构和智能试衣系统

研究背景 在信息时代和元宇宙的背景下&#xff0c;虚拟服装设计对满足服装行业的个性化需求至关重要。与传统方法不同&#xff0c;虚拟试衣节省时间、方便客户&#xff0c;并提供多样化的款式。准确得测量人体围度并重构出人体的模型是虚拟试衣的关键。为了实现动态人体重构&a…

【面试经典 150 | 二叉树层序遍历】二叉树的右视图

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;层序遍历方法二&#xff1a;深度优先搜索 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于…

【Linux】进程和计划任务

目录 一、进程介绍 1.1 进程与线程的定义 1.1.1 进程(Process)** 1.1.2 线程(Thread)** 1.1.3 进程与线程的区别 1.2 进程的特征 1.3 进程状态 1.3.1 进程的基本状态 1.3.2 进程更多的状态 1.4 进程的优先级 1.5 进程间通信 1.6 进程的分类* 二、进程管理 2.1 查看…

SpringBoot项目创建及简单使用

目录 一.SpringBoot项目 1.1SpringBoot的介绍 1.2SpringBoot优点 二.SpringBoot项目的创建 三.注意点 一.SpringBoot项目 1.1SpringBoot的介绍 Spring是为了简化Java程序而开发的&#xff0c;那么SpringBoot则是为了简化Spring程序的。 Spring 框架&#xff1a; Spring…

【UKE!】2024.4.19

2024.4.19 【你知道的都是真相。只可惜那些并不是真相的全部。】 Friday 三月十一 谷雨 <BGM “谷雨–音阙诗听”> AC :Answer Coarse,粗劣的答案 ​ CE :Compile Easily,轻松通过 ​ PC :Perfect Compile 完美的编译 ​ WA :Wonderful Answer,好答案 ​ RE :Run Exce…

【InternLM 实战营第二期作业04】XTuner微调LLM:1.8B、多模态、Agent

基础作业 训练自己的小助手认知 1.环境安装 安装XTuner 源码 # 如果你是在 InternStudio 平台&#xff0c;则从本地 clone 一个已有 pytorch 的环境&#xff1a; # pytorch 2.0.1 py3.10_cuda11.7_cudnn8.5.0_0studio-conda xtuner0.1.17 # 如果你是在其他平台&#x…

SpringSecurity源码分析3--UserDetail部分

前言&#xff1a;本章提及的类都是与用户名、密码相关的类 UserDetailsService.class 用于加载用户信息 DaoAuthenticationProvider.class 将数据库的信息拿出来进行认证 AbstractUserDetailsAuthenticationProvider.class DaoAuthenticationProvider的父类&#xff0c;通过模…

【FreeRTOS】RTOS任务的同步与互斥:(二)信号量

【FreeRTOS】RTOS任务的同步与互斥&#xff1a;&#xff08;二&#xff09;信号量 信号量概念二值信号量二值信号量概念二值信号量相关API函数二值信号量的案例设计cubeMX配置软件程序设计 计数型信号量计数型信号量概念计数型信号量相关API函数二值信号量的案例设计cubeMX配置…

VUE 页码分页封装

VUE 页码封装组件 pagination/index.vue &#xff1a; <template><div class"pagination-contianer"><el-pagination background layout"prev, pager, next" :total"total" current-change"currentChange"> </e…