揭开 Java 注解的面纱:从“黑魔法”到实战原理

news2026/3/18 8:30:36
揭开 Java 注解的面纱从“黑魔法”到实战原理很多开发者用了几年 Spring 框架依然觉得注解是某种“黑魔法”。只要在方法头上加一个符号事务就生效了缓存就加上了权限就校验了。但其实一旦你把注解从神坛上拉下来它就只是一种非常基础的元数据机制。结合一个自定义的RedisCache缓存注解让我们通过四个直击本质的问题彻底搞懂它。1. 注解的定义和语法什么是注解注解本质上就是一种**“贴在代码上的标签”**。它可以贴在类、方法、变量或参数上。非常重要的一点注解本身没有任何逻辑它不会直接影响代码的执行它只是把信息比如缓存过期时间存在那里等待被其他程序比如反射机制或 Spring AOP来读取和执行。语法拆解让我们看你提供的这段RedisCache代码它包含了注解的核心要素Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)DocumentedpublicinterfaceRedisCache{/** * 缓存 Key 的前缀例如 user:info: */StringkeyPrefix();/** * 动态 Key 的 SpEL 表达式例如 #id 或 #p0 * 如果为空默认使用方法的第一个参数作为 ID */Stringkey()default;/** * 过期时间默认 30 分钟 */longttl()default30;/** * 时间单位 */TimeUnitunit()defaultTimeUnit.MINUTES;}1. 声明关键字 (interface)底层其实就是声明了一个继承自java.lang.annotation.Annotation的接口。2. 元注解修饰标签的标签Target(ElementType.METHOD)规定这个标签只能贴在“方法”上。Retention(RetentionPolicy.RUNTIME)最关键的一句。规定这个标签在程序运行期间一直保留在内存中。如果不写这个你的切面代码在运行时根本“看”不到这个注解。Documented生成 JavaDoc 时把这个注解也收录进去。3. 属性看起来像方法其实是变量String keyPrefix();必填属性。使用时必须写RedisCache(keyPrefix ...)。long ttl() default 30;带有default的是选填属性。不写就默认是 30。2. 什么时候应该定义和使用注解当你发现代码中存在大量**“非核心业务但又无处不在的通用逻辑即横切关注点”**时就是使用注解的最佳时机。典型场景缓存控制像你的RedisCache查库前先查缓存查库后写回缓存。权限校验比如RequiresRole(ADMIN)在执行方法前先检查当前登录用户有没有权限。日志记录比如LogOperate(修改用户密码)方法执行完后自动往操作日志表里插入一条记录。事务管理著名的Transactional方法报错自动回滚数据库不用你手动写Connection.rollback()。参数校验比如NotNull、Email在进入业务逻辑前自动拦截非法参数。总结原则凡是你想在方法执行的**“前、后、异常时”**做一些通用处理并且不想让这些处理脏了你原本的业务代码就用注解结合 AOP。3. 为什么需要注解注解的核心价值在于两个词解耦和声明式编程。1. 业务逻辑更纯粹解耦如果没有RedisCache你的getUserById方法可能长这样publicUsergetUserById(Longid){Stringkeyuser:id;UseruserredisTemplate.get(key);if(user!null){returnuser;}// 核心逻辑只有这一行useruserMapper.selectById(id);redisTemplate.set(key,user,30,TimeUnit.MINUTES);returnuser;}你看真正查数据库的核心代码只有一行却被大量的 Redis 样板代码淹没了。用了注解方法里就只剩下纯粹的业务逻辑代码瞬间变得干净。2. 声明式编程你只需要**“声明你想要什么”**贴个标签说“我要缓存”而不需要“亲自去写怎么做”。这极大地提高了开发效率和代码可读性。看一眼方法头就知道这个方法具备什么额外能力。3. 消灭重复不用在每个需要缓存的方法里复制粘贴那几十行相同的 Redis 判断逻辑了。4. 除了注解还有什么其他可以替代的东西如果不用注解要实现同样的“配置或拦截”效果业界通常有以下几种替代方案方案一XML 配置传统的替代品在注解流行之前比如早期的 Spring配置全部写在巨大的 XML 文件里。做法在一个cache-config.xml文件里配置cache methodgetUserById prefixuser: ttl30/。缺点“XML 地狱”。配置文件又长又难懂且跟代码严重割裂。你要看一个方法有没有缓存还得去另一个文件夹里翻 XML。现在几乎被淘汰。方案二硬编码 / 模板模式最直接的替代品直接写一个工具类把业务逻辑包裹起来不搞 AOP不搞反射。做法// 伪代码使用函数式接口publicUsergetUserById(Longid){returnredisTemplate.executeWithCache(user:id,30,()-{returnuserMapper.selectById(id);// 真正的业务逻辑传进去});}优点执行流程极其清晰没有 AOP 的“黑魔法”出错了非常容易打断点调试。缺点有点侵入性虽然比直接写全套 Redis 代码强但依然需要在业务方法内部显式调用。方案三动态代理不基于注解的 AOPAOP 不一定要看注解。你可以配置 AOP 拦截特定命名规则的方法。做法配置切面说“凡是名字以get或select开头的方法我统统给它们加上缓存”。优点连注解都不用贴了全自动化。缺点太死板一刀切。如果某个get方法你由于特殊原因不想缓存或者想设置过期时间为 60 分钟处理起来非常麻烦。扩展元注解的常见参数详解在定义注解时Target和Retention是最核心的元注解。除了上面代码用到的还有哪些常见参数1. Target这个标签还能贴在哪里Target接收的是ElementType枚举。除了METHOD方法常用的还有参数作用范围常见框架案例TYPE类、接口、枚举Spring 的RestController、ServiceMyBatis 的Mapper。FIELD类的属性成员变量Spring 的Autowired注入 Bean、Value读取配置。PARAMETER方法的参数Spring MVC 的PathVariable、RequestBody告诉框架把前端数据塞给哪个参数。CONSTRUCTOR构造函数构造器注入时把Autowired贴在构造方法上。ANNOTATION_TYPE另一个注解上像Target和Retention自身就是贴在别的注解上的“元注解”。补充说明Target可以传入多个值。例如Target({ElementType.TYPE, ElementType.METHOD})表示该注解既能贴在类上也能贴在方法上。2. Retention这个标签能活到什么时候Retention接收的是RetentionPolicy枚举。它决定了注解的生命周期参数生命周期核心作用SOURCE只活在 .java 源码里给编译器看。编译成 .class 时会被丢弃。典型代表Override、Lombok 的Data。CLASS保留在 .class 文件里给字节码工具看。这是默认值JVM 运行时会忽略。较少在业务中使用。RUNTIME一直存活到 JVM 运行时给反射和 AOP 看。只要你想在代码运行期间动态读取配置如读取缓存过期时间必须用这个。总结如果你写注解是为了配合 AOP 做业务增强拦截方法、处理缓存、校验权限等请直接使用Retention(RetentionPolicy.RUNTIME)。如果你写注解是为了让 IDE 不报错、或者在编译时生成代码像 Lombok 那样才需要用到SOURCE。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…