在SpringBoot项目中实现切面执行链功能

1.定义切面执行链顶级接口 AspectHandler

/*** 切面执行链**/
public interface AspectHandler {/*** 设置排除项* @param excludes*/default void setExcludes(List<String> excludes) {}/*** 获取排除项* @return*/default List<String> getExcludes() {return new ArrayList<>();}/*** 前置处理* @param pjp* @return* @throws Exception*/boolean execute(ProceedingJoinPoint pjp) throws Exception;/*** 后置处理* @param pjp* @param response* @param exception*/default void afterCompletion(ProceedingJoinPoint pjp, Object response, Exception exception) {}
}

2.定义切面处理顺序注解 AspectHandlerOrder

/*** 处理器排序*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AspectHandlerOrder {/*** The order value.* <p>Default is {@link Ordered#LOWEST_PRECEDENCE}.** @see Ordered#getOrder()*/int value() default Ordered.LOWEST_PRECEDENCE;
}

3.web层统一处理切面类 AbstractWebAspect

/*** web层的统一切面,需要在使用时进行统一配置,设置切点*/
public abstract class AbstractWebAspect implements InitializingBean {private static final Logger logger = LoggerFactory.getLogger(AbstractWebAspect.class);private final static String SESSION_KEY = "sessionId";@Autowired(required = false)@Qualifier("apiAspectHandlers")private List<AspectHandler> aspectHandlers;private AntPathMatcher antPathMatcher = new AntPathMatcher();@Overridepublic void afterPropertiesSet() throws Exception {if (!CollectionUtils.isEmpty(aspectHandlers)) {Collections.sort(aspectHandlers, (o1, o2) -> {AspectHandlerOrder o1HandlerOrder = o1.getClass().getAnnotation(AspectHandlerOrder.class);AspectHandlerOrder o2HandlerOrder = o2.getClass().getAnnotation(AspectHandlerOrder.class);int o1OrderValue = o1HandlerOrder == null ? Ordered.LOWEST_PRECEDENCE : o1HandlerOrder.value();int o2OrderValue = o2HandlerOrder == null ? Ordered.LOWEST_PRECEDENCE : o2HandlerOrder.value();return o1OrderValue == o2OrderValue ? 0 : o1OrderValue > o2OrderValue ? 1 : -1;});}}public List<AspectHandler> getAspectHandlers() {return aspectHandlers;}private List<Class<? extends AspectHandler>> asList(Class<? extends AspectHandler>[] classes) {if (classes != null && classes.length > 0) {List<Class<? extends AspectHandler>> list = new ArrayList<>();for (Class<? extends AspectHandler> aClass : classes) {list.add(aClass);}return list;}return new ArrayList<>();}protected Object doAroundMethod(ProceedingJoinPoint pjp, List<AspectHandler> aspectHandlers) throws Exception {StopWatch stopWatch = new StopWatch();stopWatch.start();Exception exception = null;Object response = null;ArrayList<AspectHandler> executedAspectHandlers = new ArrayList<>();String methodName = pjp.toShortString();try {Object[] args = pjp.getArgs();logger.info("Aspect request={},args={}", methodName, Arrays.toString(args));// whether declare with AspectHandlerExclude annotation// if true pass declare excludes, default empty pass all// refactorAnnotation clazzAnnotation = getClazzAnnotation(pjp, AspectHandlerExclude.class);Annotation methodAnnotation = getMethodAnnotation(pjp, AspectHandlerExclude.class);boolean result = true;Class<? extends AspectHandler>[] methodExcludes = methodAnnotation == null ? new Class[]{} : ((AspectHandlerExclude) methodAnnotation).excludes().length == 0 ? aspectHandlers.stream().map(a -> a.getClass()).collect(Collectors.toList()).toArray(new Class[]{}) : ((AspectHandlerExclude) methodAnnotation).excludes();Class<? extends AspectHandler>[] clazzExcludes = clazzAnnotation == null ? new Class[]{} : ((AspectHandlerExclude) clazzAnnotation).excludes().length == 0 ? aspectHandlers.stream().map(a -> a.getClass()).collect(Collectors.toList()).toArray(new Class[]{}) : ((AspectHandlerExclude) clazzAnnotation).excludes();if (!CollectionUtils.isEmpty(aspectHandlers)) {aspectHandlers = new ArrayList<>(aspectHandlers);if (clazzExcludes.length > 0) {List<Class<? extends AspectHandler>> classes = asList(clazzExcludes);aspectHandlers.removeIf(h -> classes.contains(h.getClass()));}if (methodExcludes.length > 0) {List<Class<? extends AspectHandler>> classes = asList(methodExcludes);aspectHandlers.removeIf(h -> classes.contains(h.getClass()));}for (AspectHandler aspectHandler : aspectHandlers) {executedAspectHandlers.add(aspectHandler);result = aspectHandler.execute(pjp);if (!result) {break;}}}if (result) {response = pjp.proceed();if (response != null && response instanceof ApiResponse) {ApiResponse re = (ApiResponse) response;String sessionId = MDC.get(SESSION_KEY);re.setReqId(sessionId);return re;}return response;}} catch (Throwable throwable) {exception = (Exception) throwable;logger.error("execute:[{}],throw exception:[{}],message:[{}]", methodName, exception == null ? "" : exception.getClass().getName(), exception == null ? "" : exception.getMessage());throw exception;} finally {if (executedAspectHandlers.size() > 0) {for (int i = executedAspectHandlers.size() - 1; i >= 0; i--) {AspectHandler ah = executedAspectHandlers.get(i);try {ah.afterCompletion(pjp, response, exception);} catch (Exception e) {logger.error("AspectHandler afterCompletion execute error", e);}}}stopWatch.stop();long elapseTime = stopWatch.getTotalTimeMillis();logger.info("Aspect elapseTime:[{}],methodName:[{}]", elapseTime, methodName);}return response;}private void populateReqId(Object response) {}protected Object doAroundMethod(ProceedingJoinPoint pjp) throws Exception {return doAroundMethod(pjp, this.aspectHandlers);}private boolean matchExclude(AspectHandler aspectHandler, Class<? extends AspectHandler>[] excludes) {for (Class<? extends AspectHandler> exclude : excludes) {if (aspectHandler.getClass().equals(exclude)) {return true;}}HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String url = request.getRequestURI();List<String> excludeUrls = aspectHandler.getExcludes();if (!CollectionUtils.isEmpty(excludeUrls)) {for (String excludeUrl : excludeUrls) {if (antPathMatcher.match(excludeUrl, url)) {return true;}}}return false;}/*** get the annotation declare with method<br/>* if declare return the annotation,otherwise return null** @param pjp* @param annotation the annotation which find* @return*/private Annotation getMethodAnnotation(ProceedingJoinPoint pjp, Class<? extends Annotation> annotation) {Signature signature = pjp.getSignature();if (signature instanceof MethodSignature) {MethodSignature methodSignature = (MethodSignature) signature;return methodSignature.getMethod().getAnnotation(annotation);}return null;}/*** get the annotation declare with class<br/>* if declare return the annotation,otherwise return null** @param pjp* @param annotation the annotation which find* @return*/private Annotation getClazzAnnotation(ProceedingJoinPoint pjp, Class<? extends Annotation> annotation) {return pjp.getTarget().getClass().getAnnotation(annotation);}
}

4.切面配置类 AspectConfiguration

@Configuration
public class AspectConfiguration {@Beanpublic List<AspectHandler> apiAspectHandlers() {return Arrays.asList(new HttpHeaderAspectHandler(),new SecurityAspectHandler());}
}

5.定义在Http请求头中添加自定义信息切面 HttpHeaderAspectHandler

@Slf4j
@AspectHandlerOrder(Ordered.HIGHEST_PRECEDENCE)
public class HttpHeaderAspectHandler implements AspectHandler {@Overridepublic boolean execute(ProceedingJoinPoint proceedingJoinPoint) {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();Enumeration<String> headerNames = request.getHeaderNames();HttpHeader httpHeader = new HttpHeader();while (headerNames.hasMoreElements()) {String s = headerNames.nextElement();String header = request.getHeader(s);Field field = ReflectionUtils.findField(HttpHeader.class, s);if (field != null) {field.setAccessible(true);ReflectionUtils.setField(field, httpHeader, header);}}//没有按要求返回的情况,赋值默认值if(ObjectUtils.isEmpty(AppSourceEnum.self(httpHeader.getApp_source()))){httpHeader.setApp_source(AppSourceEnum.DEFAULT.getCode().toString());}WebContext.setHttpHeader(httpHeader);return true;}@Overridepublic void afterCompletion(ProceedingJoinPoint pjp, Object response, Exception exception) {AspectHandler.super.afterCompletion(pjp, response, exception);WebContext.removeHttpHeader();if (!(response instanceof ApiResponse)) {Optional.ofNullable(response).ifPresent((r) -> {log.error("controller return wrong type:" + response.getClass().getSimpleName());});return;}}
}

6.定义跳过切面注解 AspectHandlerExclude

/*** web controller中的方法加上该注解则会跳过切面逻辑**/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AspectHandlerExclude {/*** 如果excludes为空则跳过所有handler如果不为空则跳过指定的handler** @return*/Class<? extends AspectHandler>[] excludes() default {};
}

7.在controller方法上添加跳过切面配置

@AspectHandlerExclude(excludes = { SecurityAspectHandler.class })
public ApiResponse<?> findPageList(searchRequestDTO searchRequestDTO) {}

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

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

相关文章

事务与并发控制

事务&#xff08;Transaction0&#xff09;&#xff1a;要么全做&#xff0c;要么全不做&#xff1b; 事务ACID&#xff1a;原子性Atomicity&#xff1b;一致性Consistency&#xff1b;隔离性Isolation&#xff1b;持久性Durability&#xff1b; 并发操作问题&#xff1a; 1.…

基于RNN和Transformer的词级语言建模 代码分析 _generate_square_subsequent_mask

基于RNN和Transformer的词级语言建模 代码分析 _generate_square_subsequent_mask flyfish Word-level Language Modeling using RNN and Transformer word_language_model PyTorch 提供的 word_language_model 示例展示了如何使用循环神经网络RNN(GRU或LSTM)和 Transforme…

汽车IVI中控开发入门及进阶(二十二):video decoder视频解码芯片

前言: 视频解码器在许多汽车、专业和消费视频应用中仍有需求。Analog Devices是模拟视频产品领域的行业领导者,提供一系列视频解码器,可将标准(SD,standard definition)和高清(HD,High definition)分辨率的模拟视频高质量转换为MIPI或TTL格式的数字视频数据。典型的应…

【AI大模型】如何让大模型变得更聪明?基于时代背景的思考

【AI大模型】如何让大模型变得更聪明 前言 在以前&#xff0c;AI和大模型实际上界限较为清晰。但是随着人工智能技术的不断发展&#xff0c;基于大规模预训练模型的应用在基于AI人工智能的技术支持和帮助上&#xff0c;多个领域展现出了前所未有的能力。无论是自然语言处理、…

算法刷题笔记 差分矩阵(C++实现)

文章目录 题目前言题目描述解题思路和代码实现 题目前言 这道题是一道差分算法的拓展题型&#xff0c;是算法刷题笔记到目前为止我认为最困难的题目之一。因此&#xff0c;这篇题解博客的过程记录也最为详细&#xff0c;希望能够为你带来帮助。 题目描述 输入一个n行m列的整…

JavaScript的垃圾回收机制

No.内容链接1Openlayers 【入门教程】 - 【源代码示例300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3Cesium 【入门教程】 - 【源代码图文示例200】 4MapboxGL【入门教程】 - 【源代码图文示例150】 5前端就业宝典 【面试题详细答案 1000】 文章目录 一、垃圾…

匹配字符串

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 Python提供了re模块&#xff0c;用于实现正则表达式的操作。在实现时&#xff0c;可以使用re模块提供的方法&#xff08;如search()、match()、finda…

深入理解Redis:多种操作方式详解

Redis&#xff08;Remote Dictionary Server&#xff09;是一款高性能的开源键值存储系统&#xff0c;广泛应用于缓存、会话管理、实时分析等领域。它支持多种数据结构&#xff0c;如字符串、哈希、列表、集合和有序集合等&#xff0c;提供了丰富的操作命令。本篇博客将详细介绍…

信息系统项目管理师0603:项目整合管理 — 考点总结(可直接理解记忆)

点击查看专栏目录 文章目录 项目整合管理 — 考点总结(可直接理解记忆) 输入、输出、工具和技术 历年考题直接考输入,输出、工具和技术的有17年11月第34、35,19年5月第34、35,20年11月27、28,21年5月第26,28,21年11月第28,22年5月第25,22年11月第22考题 项目章程是正…

CasaOS玩客云安装全平台高速下载器Gopeed并实现远程访问

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

BufferQueue 的工作原理

bufferQueue 是 Android 图形栈中的一个核心组件,它在生产者和消费者之间传递缓冲区(buffer)。它通常用于图形缓冲区管理,特别是在 SurfaceFlinger 和其他图形相关的组件中。理解 BufferQueue 的工作原理对开发高性能图形应用和解决图形渲染问题非常有帮助。 BufferQueue …

基于Python的酒店客房入侵检测系统的设计与实现

基于Python的酒店客房入侵检测系统的设计与实现 开发语言:Python 数据库&#xff1a;MySQL所用到的知识&#xff1a;Django框架工具&#xff1a;pycharm、Navicat、Maven 系统功能实现 酒店客房入侵管理界面 结合上文的结构搭建和用户需求&#xff0c;酒店客房入侵检测系统的…

【Unity Shader入门精要 第12章】屏幕后处理效果(一)

1. 原理和过程 屏幕后处理是绑定摄像机的&#xff0c;通过抓取当前摄像机渲染的图像作为 SrcTextrue&#xff0c;然后按需依次调用处理接口&#xff0c;对 SrcTexture 进行处理&#xff0c;最后将处理完成的 DstTexture 显示到屏幕上&#xff0c;整个过程的调度通过 C# 脚本完…

使用 C++ 在当前进程中获取指定模块的基址

C 实现 , 获取指定模块在该进程中的基址 1、流程: 获取进程的所有模块信息–>遍历模块列表 2、实现&#xff1a; // 我自己定义的 typedef struct moudle_date_ {HANDLE mhandle; // 句柄char mname[64]; // 名称char* date; // 数据DWORD mdword; // 基址…

【机器学习】Adaboost: 强化弱学习器的自适应提升方法

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Adaboost: 强化弱学习器的自适应提升方法引言Adaboost基础概念弱学习器与强学习…

存储器容量小才使用SRAM芯片,容量较大时使用DRAM芯片。为什么?

在计算机系统中&#xff0c;存储器容量的选择涉及到多种因素&#xff0c;包括成本、速度和复杂性。SRAM&#xff08;静态随机存取存储器&#xff09;和DRAM&#xff08;动态随机存取存储器&#xff09;是两种常见的内存类型&#xff0c;它们在设计和应用上有显著的不同。以下是…

【蓝桥杯嵌入式】 第六届国赛

目录 题目 配置 注意事项 代码 - 默写大师 EEPROM读写函数 LED驱动函数 ADC采集 上电初始化 LCD 按键 PWM互补输出 全部代码 hardware.c hardware.h control.c control.h main.c 题目 配置 注意事项 复制LCD的工程&#xff0c;先配置资源 --- 勾选完选项一…

CCIG 2024:合合信息文档解析技术突破与应用前景

目录 背景当前大模型训练和应用面临的问题训练Token耗尽训练语料质量要求高LLM文档问答应用中文档解析不精准 合合信息的文档解析技术1. 具备多文档元素识别能力2. 具备版面分析能力3. 高性能的文档解析4. 高精准、高效率的文档解析文档多板式部分示例 文档解析典型技术难点元素…

【代码随想录Day23】|669.修建二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 这题最开始的想法是复用删除节点的那题的思路做&#xff0c;需要修改的部分就是要让程序删除完一个点后继续遍历&#xff0c;因为后续可能还有不符合条件的节点。但这样想也做复杂了。 这类题其实不用想用什么序遍历&#xff0c;用哪种方式只是为了更好的…

案例|开发一个美业小程序,都有什么功能

随着移动互联网的迅猛发展&#xff0c;美业连锁机构纷纷寻求数字化转型&#xff0c;以小程序为载体&#xff0c;提升服务效率&#xff0c;增强客户体验。 线下店现在面临的困境&#xff1a; 客户到店排队时间过长&#xff0c;体验感受差 新客引流难&#xff0c;老用户回头客…