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. 使用原则:通用功能用内置注解,专属业务逻辑用自定义注解。
相关推荐
低调小一2 小时前
OpenClaw 从安装到可用:把 Tools/Skills 变成“可控操控面板”,并用飞书做远程入口
java·大数据·人工智能·飞书·openclaw·clawbot·skil
CRMEB系统商城2 小时前
CRMEB标准版系统(PHP)v6.0公测版发布,商城主题市场上线~
java·开发语言·小程序·php
姗姗的鱼尾喵2 小时前
Java 面试内容分享
java·spring boot·面试
渡过晚枫2 小时前
[第十六届蓝桥杯/java]2.2025
java·职场和发展·蓝桥杯
6+h2 小时前
【Spring】Service层常用注解详解
java·后端·spring
REDcker2 小时前
Linux C++ 内存泄漏排查分析手册
java·linux·c++
杰克尼2 小时前
苍穹外卖--day11
java·数据库·spring boot·mybatis·notepad++
weixin199701080162 小时前
搜好货商品详情页前端性能优化实战
java·前端·python
XiYang-DING2 小时前
【Java SE】Java代码块详解
java·开发语言·python