当前位置: 首页 > news >正文

【Quarkus】基于CDI和拦截器实现AOP功能(进阶版)

Quarkus 基于CDI和拦截器实现AOP功能(进阶版)

      • 拦截器的属性成员
      • 拦截器的重复使用
      • 基于属性成员和重复使用的拦截器的发消息案例

本节来了解一下拦截器高级特性(拦截器的重复使用和属性成员),官网说明:https://cn.quarkus.io/guides/cdi-reference#repeatable-interceptor-bindings。

拦截器的属性成员

拦截器自己是个注解,而注解是有属性的,所以我们时可以在自定义的拦截器注解中添加属性成员的,这样在拦截器使用的时候有更多扩展空间。

💡注意:很重要,quarkus对属性成员使用时的限制是这些属性成员必须是要被@Nonbinding注解所标注的,否则在使用有设置属性的拦截器时该拦截器功能不会生效。

@Nonbinding

  • 注解用于 CDI(Contexts and Dependency Injection)中的自定义注解,以标记不影响注解唯一性的属性。换句话说,当你使用 @InterceptorBinding 创建自定义注解并将其应用于拦截器时,默认情况下所有属性都参与注解的唯一性判断。这意味着,如果两个注解的属性值不同,它们将被视为不同的注解。
  • 有时你可能希望某些属性不影响注解的唯一性。这时你就可以使用 @Nonbinding 注解这些属性,使其在比较注解时被忽略。
  • 当你创建自定义注解并在拦截器上使用时,如果该注解有属性且这些属性未被标记为 @Nonbinding,这些属性将会影响注解的唯一性判断。这意味着拦截器上使用的注解和方法上使用的注解必须完全一致(包括所有属性的值),否则拦截器不会生效。
  • 在自定义注解的属性上添加 @Nonbinding 注解,使这些属性不影响注解的唯一性判断。这样,拦截器上使用的注解和方法上使用的注解可以被认为是相同的,即使它们的属性值不同,这样拦截器就会生效。

示例代码

package com.xxx.interceptor;import javax.enterprise.util.Nonbinding;
import javax.interceptor.InterceptorBinding;
import java.lang.annotation.*;@InterceptorBinding
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SendMessage {/*** 消息类型 : "sms"表示短信,"email"表示邮件*/@NonbindingString sendType() default "sms";
}

拦截器的重复使用

允许在同一位置重复使用同一个注解,这是java注解的通用功能,并非quarkus独有,但是在quarkus中使用时有些需要注意的限制。

quarkus对重复使用同一拦截器注解的限制:

  1. 可以作用在方法上
  2. 不能作用在类上
  3. 不能作用在stereotypes上

关于2和3,官方的说法是将来会解决(This might be added in the future)

示例代码

package com.bolingcavalry.interceptor.define;import javax.enterprise.util.Nonbinding;
import javax.interceptor.InterceptorBinding;
import java.lang.annotation.*;@InterceptorBinding
@Repeatable(SendMessage.SendMessageList.class)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SendMessage {/*** 消息类型 : "sms"表示短信,"email"表示邮件*/@NonbindingString sendType() default "sms";@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@interface SendMessageList {SendMessage[] value();}
}

基于属性成员和重复使用的拦截器的发消息案例

要求设计一个拦截器,名为SendMessage,功能是对外发送通知,通知的方式有短信和邮件两种,具体用哪种是可以通过拦截器属性设置的。

有个SendMsg的普通接口,此接口有三个实现类:SendMsgA、SendMsgB、SendMsgC,这些实现类都是bean,代码如下:

public interface SendMsg {String send();
}@ApplicationScoped
@Named("A")
public class SendMsgA implements SendMsg {@Overridepublic void send() {Log.info("send from A");}
}@ApplicationScoped
@Named("B")
public class SendMsgB implements SendMsg {@Overridepublic void send() {Log.info("send from B");}
}@ApplicationScoped
@Named("C")
public class SendMsgC implements SendMsg {@Overridepublic void send() {Log.info("send from C");}
}

需求:

  • 用SendMessage拦截器拦截SendMsgA,通知类型是短信
  • 用SendMessage拦截器拦截SendMsgB,通知类型是邮件
  • 用SendMessage拦截器拦截SendMsgC,通知类型是短信和邮件都发送

代码:

package com.xxx.interceptor;import javax.enterprise.util.Nonbinding;
import javax.interceptor.InterceptorBinding;
import java.lang.annotation.*;@InterceptorBinding
@Repeatable(SendMessage.SendMessageList.class)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SendMessage {/*** 消息类型 : "sms"表示短信,"email"表示邮件*/@NonbindingString sendType() default "sms";@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@interface SendMessageList {SendMessage[] value();}
}
package com.xxx.interceptor.impl;import com.xxx.interceptor.SendMessage;
import com.xxx.interceptor.TrackParams;
import io.quarkus.arc.Priority;
import io.quarkus.arc.runtime.InterceptorBindings;
import io.quarkus.logging.Log;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import java.lang.annotation.Annotation;
import java.util.*;
import static io.quarkus.arc.ArcInvocationContext.KEY_INTERCEPTOR_BINDINGS;@SendMessage
@Interceptor
public class SendMessageInterceptor {@AroundInvokeObject execute(InvocationContext context) throws Exception {// 取出所有注解,由于允许重复注解,因此通知类型可能有多个Set<Annotation> bindings = InterceptorBindings.getInterceptorBindings(invocationContext);// 获取被拦截方法的类名String interceptedClass = context.getTarget().getClass().getSimpleName();// ...// 先执行被拦截的方法Object rlt = context.proceed();// ...// 最后再返回方法执行结果return rlt;}
}

@ApplicationScoped
@Named("A")
public class SendMsgA implements SendMsg {@SendMessage@Overridepublic void send() {Log.info("send from A");}
}@ApplicationScoped
@Named("B")
public class SendMsgB implements SendMsg {@SendMessage(sendType = "email")@Overridepublic void send() {Log.info("send from B");}
}// 注意这里使用了两次SendMessage
@ApplicationScoped
@Named("C")
public class SendMsgC implements SendMsg {@SendMessage@SendMessage(sendType = "email")@Overridepublic void send() {Log.info("send from C");}
}

相关文章:

【Quarkus】基于CDI和拦截器实现AOP功能(进阶版)

Quarkus 基于CDI和拦截器实现AOP功能&#xff08;进阶版&#xff09; 拦截器的属性成员拦截器的重复使用基于属性成员和重复使用的拦截器的发消息案例 本节来了解一下拦截器高级特性&#xff08;拦截器的重复使用和属性成员&#xff09;&#xff0c;官网说明&#xff1a;https:…...

【踩坑日记】【教程】如何在ubuntu服务器上配置公钥登录以及bug解决

前言 在日常开发和运维中&#xff0c;为了提高服务器登录的安全性&#xff0c;我们通常会选择使用 SSH 密钥认证 来替代传统的密码登录。然而&#xff0c;在配置 SSH 公钥登录的过程中&#xff0c;可能会遇到各种坑和 Bug。本文将从零开始&#xff0c;手把手教你如何在 Ubuntu…...

insmod一个ko提供基础函数供后insmod的ko使用的方法

一、背景 在内核模块开发时&#xff0c;多个不同的内核模块&#xff0c;有时候可能需要都共用一些公共的函数&#xff0c;比如申请一些平台性的公共资源。但是&#xff0c;这些公共的函数又不方便去加入到内核镜像里&#xff0c;这时候就需要把这些各个内核模块需要用到的一些…...

七、传统循环神经网络(RNN)

传统循环神经网络 RNN 前言一、RNN 是什么&#xff1f;1.1 RNN 的结构1.2 结构举例 二、RNN 模型的分类2.1 按照 输入跟输出 的结构分类2.2 按照 内部结构 分类 三、传统 RNN 模型3.1 RNN内部结构图3.2 内部计算公式3.3 其中 tanh 激活函数的作用3.4 传统RNN优缺点 四、代码演示…...

LeetCode:19.删除链表倒数第N个节点

跟着carl学算法&#xff0c;本系列博客仅做个人记录&#xff0c;建议大家都去看carl本人的博客&#xff0c;写的真的很好的&#xff01; 代码随想录 LeetCode&#xff1a;19.删除链表倒数第N个节点 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表…...

【RISC-V CPU debug 专栏 2 -- Debug Module (DM), non-ISA】

文章目录 调试模块(DM)功能必须支持的功能可选支持的功能兼容性要求规模限制Debug Module Interface (DMI)总线类型地址与操作地址空间控制机制Debug Module Interface Signals请求信号响应信号信号流程Reset Control复位控制方法全局复位 (`ndmreset`)Hart 复位 (`hartreset…...

单片机学习笔记 11. 外部中断

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…...

基于stm32的智能教室管理系统/智能家居系统

基于stm32的智能教室管理系统/智能家居系统 持续更新&#xff0c;欢迎关注!!! ** 基于stm32的智能教室管理系统/智能家居系统 ** 目前&#xff0c;物联网已广泛应用在我们的生活中。智慧校园是将校园中的生活、学习、工作等相关的资源联系在一起&#xff0c;实现管理的智能化…...

基于 Qt 和 GStreamer 的环境中构建播放器

一、功能与需求分析 功能描述 播放本地视频文件(如 MP4、MKV)。 支持基本控制功能(播放、暂停、停止、跳转)。 提供音量调节功能。 在 Windows 环境下使用 Visual Studio 2022 编译。 技术选型 Qt:用于构建用户界面。 GStreamer:负责视频解码和播放。 Visual Studio 202…...

windows docker 入门

这个教程将指导你如何安装Docker、运行第一个容器以及理解一些基本概念。 第一步&#xff1a;安装Docker Desktop for Windows 系统要求&#xff1a; Windows 10 64位版本&#xff08;专业版、企业版或教育版&#xff09;。启用Hyper-V和Windows Subsystem for Linux (WSL 2)。…...

baomidou Mabatis plus引入异常

1 主要异常信息 Error creating bean with name dataSource 但是有个重要提示 dynamic-datasource Please check the setting of primary 解决方法&#xff1a; <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring…...

深度学习中的正则化模型是什么意思?

一、定义 在深度学习中&#xff0c;正则化是一种用于防止过拟合的技术。过拟合是指模型在训练数据上表现非常好&#xff0c;但在新的、未见过的数据&#xff08;测试数据&#xff09;上表现很差的情况。正则化模型就是通过在损失函数中添加额外的项来约束模型的复杂度&#xf…...

修改IDEA配置导致Spring Boot项目读取application.properties中文乱码问题

之前很多配置都是放在nacos里面&#xff0c;然后这次同事有个配置写在application.properties中&#xff0c;这个配置含有中文&#xff0c;启动之后发现拿到的中文值会乱码&#xff0c;然后就帮忙看了一下问题。 排查问题 经过不停的百度、排查发现&#xff0c;spring读取app…...

Flink 热存储维表 使用 Guava Cache 减轻访问压力

目录 背景 Guava Cache 简介 实现方案 1. 项目依赖 2. Guava Cache 集成到 Flink (1) 定义 Cache (2) 使用 Cache 优化维表查询 3. 应用运行效果 (1) 维表查询逻辑优化 (2) 减少存储压力 Guava Cache 配置优化 总结 背景 在实时计算场景中&#xff0c;Flink 应用中…...

深入探索SenseVoiceSmall:高效多语言语音识别与处理模型

引言 随着人工智能技术的飞速发展&#xff0c;语音识别技术已经广泛应用于智能助手、客户服务、智能家居等多个领域。然而&#xff0c;现有的语音识别模型往往存在资源消耗大、多语言支持不足等问题。今天&#xff0c;我们要介绍的是来自ModelScope平台的SenseVoiceSmall模型&…...

Flink--API 之Transformation-转换算子的使用解析

目录 一、常用转换算子详解 &#xff08;一&#xff09;map 算子 &#xff08;二&#xff09;flatMap 算子 &#xff08;三&#xff09;filter 算子 &#xff08;四&#xff09;keyBy 算子 元组类型 POJO &#xff08;五&#xff09;reduce 算子 二、合并与连接操作 …...

每日十题八股-2024年11月27日

1.类型互转会出现什么问题吗&#xff1f; 2.为什么用bigDecimal 不用double &#xff1f; 3.装箱和拆箱是什么&#xff1f; 4.Java为什么要有Integer&#xff1f; 5.Integer相比int有什么优点&#xff1f; 6.那为什么还要保留int类型&#xff1f; 7.说一下 integer的缓存 8.怎么…...

OpenCV截取指定图片区域

import cv2 img cv2.imread(F:/2024/Python/demo1/test1/man.jpg) cv2.imshow(Image, img) # 显示图片 #cv2.waitKey(0) # 等待按键x, y, w, h 500, 100, 200, 200 # 示例坐标 roi img[y:yh, x:xw] # 截取指定区域 cv2.imshow(ROI, roi) cv2.waitKey(0) cv…...

Java部分新特性

模式匹配 instance of 模式匹配 之前写法 public void print(Object o) {if (o instanceof String){String str (String) obj;System.out.println("This is a String of length " s.length());} else {System.out.println("This is not a String");} …...

【SpringBoot】28 API接口防刷(Redis + 拦截器)

Gitee仓库 https://gitee.com/Lin_DH/system 介绍 常用的 API 安全措施包括&#xff1a;防火墙、验证码、鉴权、IP限制、数据加密、限流、监控、网关等&#xff0c;以确保接口的安全性。 常见措施 1&#xff09;防火墙 防火墙是网络安全中最基本的安全设备之一&#xff0c…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...