在我看来,常见的注解无非也就这几个:@Resource、 @Data、@Autowired、@RequestBody、@RequestParam、@Override、@Param
下面我结合用在哪里、怎么用、什么时候用/不该用、最常见使用误区来解释。
1)@Resource(JSR-250,依赖注入)
用在哪里
- 类的字段上(也可以在 setter 上),用于注入 Bean。
业务场景:例如我们要写一个关于第三方服务的代码时,我们就会这样来用
@Resource
private WxNotification wxNotification;// 会注入一个名为 wxNotification的 Bean
怎么注入(规则)
-
默认按 name 注入:字段名 = Bean 名称优先匹配(这里的name 就是wxNotification)⭐
-
找不到再按 type 注入(不同实现会略有差异,但核心是"优先名字")
什么时候用
-
你想优先按name注入(比如同一接口有多个实现时)
-
常用的习惯用
@Resource
什么时候不建议用
- 依赖很多、可读性想更统一时(团队更推荐
@Autowired + @Qualifier或构造器注入)
常见坑
-
同类型多个 Bean:字段名不匹配,会报找不到或注入错对象
-
字段名改了,注入就变了(因为按 name)
2)@Autowired(Spring,依赖注入)
用在哪里
- 字段 / 构造器 / setter 上注入 Bean
推荐:构造器注入
private final AdminMapper adminMapper;
@Autowired
public AdminService(AdminMapper adminMapper) {
this.adminMapper = adminMapper;
}
注入规则
-
按 type 注入为主⭐
-
如果有多个符合类型的 Bean(例如有多个
AdminService的实现),Spring 会根据 Bean 的名称来选择,或者抛出异常,提示你进行进一步配置。
什么时候用
- 你想按类型注入,项目都是 Spring 体系
什么时候不建议用
-
字段注入虽然常见,但不推荐(难测、不可变性差)
-
最佳实践:构造器注入 (不一定要显式写
@Autowired,新版本 Spring 单构造器可省略)
| 注解 | 默认注入方式 | 适用场景 | 备注 |
|---|---|---|---|
@Autowired |
按 type 注入 | - 通用场景。 - 不同类型的 Bean 时,通过 @Qualifier 区分。 |
推荐使用,更灵活。可以使用构造器注入。 |
@Resource |
按 name 注入 | - 明确希望按 名称 来注入。 - Bean 名称与字段名一致时。 | 适用于老项目或希望通过名称匹配 Bean 时。 |
3)@Data(Lombok,生成 getter/setter 等)
用在哪里
-
类上(DTO/VO/实体类最常见)
@Data
public class StateDto
{ private Long id;
private Integer state; }
它做了什么
自动生成:
-
getter/setter
-
toString
-
equals/hashCode
-
requiredArgsConstructor(注意版本/组合注解)
什么时候用
-
DTO/VO 这种纯数据对象,省代码
-
你希望 Spring/Jackson 能通过 setter/getter 正常绑定 JSON
什么时候不建议用
-
JPA 实体/领域对象等对 equals/hashCode 很敏感的对象(可能引发性能或逻辑问题)
-
需要精细控制 getter/setter/equals 的场景
常见坑
- boolean 字段命名(
isXxx)容易和 JSON 映射产生歧义(建议用private Boolean published;或明确@JsonProperty)
4)@RequestBody(Spring MVC,把 HTTP Body 解析成对象)
用在哪里
-
Controller 方法参数上
@PostMapping("/updateState")
public void updateState(
@RequestBody UpdateStateDto dto
)
{ ... }
什么时候用
-
前端发的是 JSON body(Content-Type: application/json)
-
POST/PUT/PATCH 携带 JSON
什么时候不该用
-
你是从 URL 参数拿值(
?id=1)→ 用@RequestParam -
你是从路径拿值(
/aaaa/1)→ 用@PathVariable -
GET 请求一般不建议用 body(很多网关/代理不稳定)
常见坑
-
忘了加
@RequestBody→ 你去F12 里 body 有值,后端对象却全是 null -
前端 Content-Type 不是 application/json → 解析失败
5)@RequestParam(Spring MVC,从 URL Query 或 form 表单取参数)
用在哪里
-
Controller 方法参数上
@GetMapping("/detail")
public void detail(
@RequestParam("id") Long id) { ... }
什么时候用
-
参数在 URL 上:
/detail?productId=435 -
或者
application/x-www-form-urlencoded表单提交
什么时候不该用
-
参数在 JSON body 里(那用
@RequestBody) -
参数在路径里(那用
@PathVariable)
常见坑
-
required = true默认必须传,不传会 400需要可选就写:
@RequestParam(value="id", required=false) Long id
6)@Override(Java 语法标记:重写父类/接口方法)
用在哪里
-
方法上
@Override
public void updateState(UpdateStateDto dto) { ... }
作用
-
编译器检查你是否真的在"重写"
-
防止你方法名写错、参数写错导致没重写成功
什么时候用
- 只要是实现接口/重写父类方法,强烈建议一直加
什么时候不该用
- 不重写的时候当然不能用(会编译报错)
7)@Param(MyBatis,给 Mapper 方法参数命名,供 XML 使用)
用在哪里
-
Mapper 接口方法参数上(多个参数时)
int updateProductState(@Param("id") Long id, @Param("isTrue") Integer isTrue);
什么时候必须用
-
方法参数 ≥ 2 个 ,并且 XML 用
#{id}这种"自定义名字" -
参数名更可读、更稳定
什么时候可以不用
-
Mapper 只有 1 个参数:
-
单值:
Long id -
或 DTO:
UpdateStateDto dto
-
-
但即使 1 个参数,为了统一风格也可以用(不是必须)
常见坑(很高频)
-
没加
@Param,XML 写#{id}→ 找不到参数,报 BindingException 或取不到值 -
@Param("id")但 XML 写#{IId}→ 对不上也不行
一张"选择注解"速查表(最实用)
Controller 参数来自哪里?
-
JSON body →
@RequestBody -
URL query:
?a=1→@RequestParam -
URL path:
/a/1→@PathVariable(你没列但你会用到) -
Header →
@RequestHeader -
Cookie →
@CookieValue
MyBatis XML 里用 #{xxx} 怎么保证取到?
-
Mapper 1 个参数(DTO 或单值)→ 通常不用
@Param -
Mapper 多参数 → 给每个参数加
@Param("xxx"),XML 用同名#{xxx}
结合你当前代码的"落地建议"
-
Controller 接口 :前端传 JSON,就用
@RequestBody UpdateStateDto dto -
Mapper update 方法 :如果你是两个参数,就必须
@Param("id")、@Param("isTrue") -
依赖注入:
@Autowired/@Resource选一个团队统一;建议构造器注入(更稳)
如果你把 Controller 那个接口方法 和 updateProductPublishState 的 mapper 方法签名贴一下(两行就够),我可以直接按你的代码指出:哪些注解该加、该加在哪、为什么。