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 框架的注解解析器(如 AnnotationConfigApplicationContext、BeanPostProcessor)或自定义解析逻辑(反射、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. 使用原则:通用功能用内置注解,专属业务逻辑用自定义注解。
相关推荐
马剑威(威哥爱编程)3 分钟前
【AI全栈后端12-08】Spring Boot 用 MCP 统一接入内部系统:让 AI 接一次,全公司复用
java·人工智能·spring boot
顽疲10 分钟前
从零用 Java 实现小红书 SpringBoot Vue UniApp(23)笔记话题多对多:一条笔记进多个话题池
java·vue.js·spring boot
bst@微胖子16 分钟前
Spring AI (5) : MCP 深度实战:从工具抽取到鉴权,SSE 与 STDIO
人工智能·spring·dubbo
打工仔折腾 AI22 分钟前
FaceFusion本地换脸实战:Windows整合包、模型选择与遮罩调参记录
人工智能·windows·后端·python·深度学习·性能优化·ai agent 实战
木井巳23 分钟前
【BFS 解决拓扑排序】课程表
java·算法·leetcode·广度优先·宽度优先·推荐算法·图搜索算法
Crazy________35 分钟前
05Linux内存管理核心原理与运维实战
java·开发语言
Nebula_g37 分钟前
JavaSE拓展:工具类Executors
java·开发语言·后端·spring·基础·javase
扶风ff43 分钟前
练题簿在线免费刷题:会员线下组卷、Word 试卷与成绩导入,课堂检测更方便
java·开发语言·算法·小程序·word
鱼宵44 分钟前
Spring AI 可观测与透明化:traceId 串起全链路,思考过程实时直播给用户
java·人工智能·spring·链路追踪·springai
RaaS1001 小时前
AI网关能做Prompt注入防护吗?AI网关核心功能详解
前端·后端