Spring 内置注解 和自定义注解的异同

要理解 Spring 内置注解和自定义注解的异同,我们可以先从注解的本质入手,再结合 Spring 框架的特性展开分析,这样能让你更清晰地把握核心区别和联系。

一、核心概念铺垫

注解(Annotation)是 Java 5 引入的语法元数据,本质是标记 + 数据载体,本身不直接执行逻辑,需要通过反射、AOP、处理器(Processor)等机制解析后才能发挥作用。Spring 框架的核心就是通过解析各种注解,实现 IoC 容器管理、AOP 增强、事务控制等功能。

二、相同点

  1. 底层语法一致 无论是 Spring 内置注解(如 @Autowired@Service)还是自定义注解,都基于 Java 注解的语法规则定义:

    • 都需要用 @interface 声明;
    • 都可以使用元注解(如 @Target@Retention@Documented@Inherited)限定作用范围、生命周期等;
    • 都可以定义属性(如 @RequestMapping(value = "/user") 中的 value)。
  2. 解析机制相通 两者都需要 Spring 框架的注解解析器(如 AnnotationConfigApplicationContextBeanPostProcessor)或自定义解析逻辑(反射、AOP)来识别和处理:

    • Spring 内置注解由 Spring 原生的解析器处理(如 AutowiredAnnotationBeanPostProcessor 解析 @Autowired);
    • 自定义注解需要你自己编写解析逻辑(如通过 AOP 切面、自定义 BeanPostProcessor)。
  3. 作用目标一致 都可以作用于类、方法、字段、参数等位置(由 @Target 元注解决定),最终目的都是为了简化开发、实现逻辑解耦(如替代 XML 配置、标记特殊逻辑)。

三、不同点

表格

维度 Spring 内置注解 自定义注解
定义主体 Spring 框架团队预先定义,随 Spring 包发布 开发者根据业务需求自行定义
功能定位 实现框架核心能力(IoC、AOP、事务、MVC 等) 实现业务定制化需求(如接口限流、日志标记、数据校验)
解析支持 Spring 原生提供解析器,开箱即用 需开发者手动编写解析逻辑(AOP / 反射 / 处理器)
通用性 通用型,适配绝大多数开发场景 专用型,仅适配自身业务场景
兼容性 与 Spring 版本强绑定,升级可能有语法变化 完全由开发者控制,兼容性自主保障
代码示例对比
1. Spring 内置注解(开箱即用)
复制代码
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

// Spring 内置注解:标记为服务层 Bean,由 IoC 容器管理
@Service
public class UserService {
    // Spring 内置注解:自动注入依赖
    @Autowired
    private UserMapper userMapper;

    public void queryUser() {
        // 业务逻辑
    }
}

无需额外解析代码,Spring 容器启动时会自动识别 @Service 并创建 Bean,识别 @Autowired 并完成依赖注入。

2. 自定义注解(需手动解析)

步骤 1:定义自定义注解

复制代码
import java.lang.annotation.*;

// 元注解:限定作用于方法
@Target(ElementType.METHOD)
// 元注解:运行时保留(可通过反射解析)
@Retention(RetentionPolicy.RUNTIME)
// 元注解:生成文档时包含
@Documented
public @interface LogOperation {
    // 注解属性:操作描述,默认值为空
    String value() default "";
}

步骤 2:编写解析逻辑(AOP 切面)

复制代码
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

// 标记为切面类
@Aspect
@Component
public class LogOperationAspect {
    // 切点:匹配所有标注了 @LogOperation 的方法
    @AfterReturning("@annotation(logOperation)")
    public void log(JoinPoint joinPoint, LogOperation logOperation) {
        // 通过反射解析注解属性
        String operation = logOperation.value();
        String methodName = joinPoint.getSignature().getName();
        // 执行自定义逻辑:打印操作日志
        System.out.println("操作日志:方法[" + methodName + "],描述[" + operation + "]");
    }
}

步骤 3:使用自定义注解

复制代码
@Service
public class OrderService {
    // 使用自定义注解,标记操作描述
    @LogOperation("创建订单")
    public void createOrder() {
        // 业务逻辑
        System.out.println("订单创建成功");
    }
}

执行 createOrder() 方法后,控制台会输出:操作日志:方法[createOrder],描述[创建订单]

四、使用场景建议

  • 优先用内置注解 :实现 IoC 容器管理(@Component/@Service)、依赖注入(@Autowired)、事务控制(@Transactional)等通用功能时,直接用 Spring 内置注解,无需重复造轮子。
  • 自定义注解场景:需要标记业务专属逻辑时(如接口权限校验、操作日志、数据脱敏、接口限流),通过自定义注解 + 解析逻辑实现,让代码更简洁、易维护。

总结

  1. 相同点:两者都基于 Java 注解语法,都需要解析机制才能生效,核心作用都是 "标记 + 数据载体";
  2. 核心区别:内置注解由 Spring 定义并提供原生解析支持,用于框架通用能力;自定义注解由开发者定义,需手动编写解析逻辑,用于业务定制化需求;
  3. 使用原则:通用功能用内置注解,专属业务逻辑用自定义注解。
相关推荐
scott.cgi5 小时前
Unity直接编译Java文件作为插件,导致失败的两个打包设置
java·unity·unity调用java·unity的java文件·unity的android插件·unity调用android·unity加载java代码
澈2079 小时前
C++并查集:高效解决连通性问题
java·c++·算法
易安说AI9 小时前
Codex 直接住进 JetBrains IDE 里:AI Agent 正在接管熟悉的开发入口
后端
子兮曰10 小时前
Node.js v26.1.0 深度解读:FFI、后量子密码与调试器的进化
前端·后端·node.js
霸道流氓气质11 小时前
基于 Milvus Lite 的 Spring AI RAG 向量库实践方案与示例
人工智能·spring·milvus
2401_8734794011 小时前
运营活动被薅羊毛怎么防?用IP查询+设备指纹联动封堵漏洞
java·网络·tcp/ip·github
ShiJiuD66688899911 小时前
大事件板块一
java
摇滚侠11 小时前
@Autowired 和 @Resource 的区别
java·开发语言
Wy_编程11 小时前
go语言中的结构体
开发语言·后端·golang
SeaTunnel11 小时前
(八)收官篇 | 数据平台最后一公里:数据集成开发设计与上线治理实战
java·大数据·开发语言·白鲸开源