今天遇到一个奇怪的问题,在配置类中注册了一个拦截器:
public class WebConfig implements WebMvcConfigurer {
private AuthInterceptor authInterceptor;
public void addInterceptors(InterceptorRegistry registry) {
// 注册拦截器,并指定拦截路径
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**") // 拦截所有路径
.excludePathPatterns("/login",
"/login/sendCode/*"); // 排除登录和注册接口
}
}
这里的authInterceptor
属性表示的拦截器使用@Resource
进行注入。其定义:
public class AuthInterceptor implements HandlerInterceptor {
private final RedisToken redisToken;
private final UserService userService;
public AuthInterceptor(RedisToken redisToken, UserService userService) {
this.redisToken = redisToken;
this.userService = userService;
}
// ...
}
使用构造器注入两个属性,构造器上的@Autowrired
注解省略掉了。
看上去似乎没有问题,但实际编译就会遇到吊轨的事情,有时候能编译通过,有时候又不能,还会随着 JVM 版本的同步反复横跳。
但,如果在配置类中使用@Autowired
注入,就不会有类似的问题。
因此就有了这篇文章,以下内容都是 DeepSeek 的马甲腾讯元宝生成的。
@Autowired
和 @Resource
都是用于依赖注入的注解,但它们在来源、匹配方式、默认行为等方面有显著区别。以下是详细对比和用法说明:
1. 来源与规范
注解 | 来源 | 规范 |
---|---|---|
@Autowired |
Spring 框架提供 | 属于 Spring 特有的注解 |
@Resource |
Java 标准注解(JSR-250) | 属于 Java EE(现 Jakarta EE)规范,Spring 也支持 |
注意:
@Resource
在 Java 9+ 中被标记为@Deprecated
(但仍可用),推荐使用jakarta.annotation.Resource
(Jakarta EE 8+)。如果项目使用纯 Spring 生态,优先用
@Autowired
;如果需要跨框架兼容(如 Java EE),可用@Resource
。
2. 匹配方式
特性 | @Autowired |
@Resource |
---|---|---|
默认匹配规则 | 按 类型(Type) 匹配 | 按 名称(Name) 匹配 |
支持按名称匹配 | 需配合 @Qualifier 使用 |
直接通过 name 或字段名匹配 |
多候选 Bean 时的行为 | 报错(需用 @Qualifier 指定) |
报错(需确保名称唯一) |
示例对比
java
复制
// 假设有两个相同类型的 Bean @Service("userService1") public class UserServiceImpl1 implements UserService {} @Service("userService2") public class UserServiceImpl2 implements UserService {}
(1) @Autowired + @Qualifier(按名称匹配)
java
复制
@Autowired @Qualifier("userService1") // 明确指定要注入的 Bean 名称 private UserService userService;
(2) @Resource(按名称匹配)
java
复制
@Resource(name = "userService1") // 直接指定名称 private UserService userService;
或通过字段名匹配(默认按字段名查找 Bean):
java
复制
@Resource // 默认匹配名为 "userServiceImpl1" 的 Bean(需配合 @Service("userServiceImpl1")) private UserService userService; // 字段名为 userService → 尝试匹配名为 "userService" 的 Bean
3. 是否支持非必需依赖
注解 | 是否支持 required=false |
行为 |
---|---|---|
@Autowired |
支持 | @Autowired(required = false) 表示依赖可选(找不到 Bean 时注入 null ) |
@Resource |
不支持 | 如果找不到匹配的 Bean,直接抛出 NoSuchBeanDefinitionException |
示例
java
复制
// @Autowired 允许可选依赖 @Autowired(required = false) private OptionalDependency optionalDependency; // 找不到时注入 null // @Resource 必须找到 Bean,否则报错 @Resource private RequiredDependency requiredDependency; // 找不到时抛异常
4. 对集合类型的支持
注解 | 对 List /Map 的支持 |
行为 |
---|---|---|
@Autowired |
支持 | 自动注入所有匹配类型的 Bean(List<BeanType> )或按名称映射的 Map(Map<String, BeanType> ) |
@Resource |
不支持直接注入集合 | 需通过 @Resource(name = "beanName") 逐个注入 |
示例
java
复制
// @Autowired 注入所有 UserService 实现 @Autowired private List<UserService> userServiceList; // 包含 userService1 和 userService2 // @Resource 无法直接注入集合,需手动处理 @Resource(name = "userService1") private UserService userService1; @Resource(name = "userService2") private UserService userService2;
5. 与构造函数/Setter 方法的配合
注解 | 构造函数注入 | Setter 方法注入 |
---|---|---|
@Autowired |
支持(Spring 4.3+ 可省略 @Autowired ) |
支持 |
@Resource |
不支持(仅支持字段或方法注入) | 支持 |
示例
java
复制
// @Autowired 构造函数注入(Spring 4.3+ 可省略注解) @Service public class OrderService { private final UserService userService; public OrderService(UserService userService) { // 无需 @Autowired this.userService = userService; } } // @Resource 构造函数注入(不支持) // 错误示例!@Resource 不能用于构造函数 //@Resource //public OrderService(UserService userService) {}
6. 性能差异
-
@Autowired
: Spring 原生注解,直接与 Spring 容器交互,性能略高(但差异可忽略)。 -
@Resource
: 需通过反射调用 Java 标准注解机制,可能稍慢(实际场景中无显著影响)。
7. 如何选择?
场景 | 推荐注解 |
---|---|
纯 Spring 项目 | 优先使用 @Autowired (更灵活,支持构造函数注入) |
需要跨框架兼容 | 使用 @Resource (如 Java EE 环境) |
按名称匹配依赖 | 两者均可,但 @Resource 更直观 |
可选依赖 | 必须用 @Autowired(required = false) |
集合类型注入 | 必须用 @Autowired |
8. 完整代码示例
场景:注入一个可选的 UserService
使用 @Autowired
java
复制
@Service public class OrderService { private final UserService userService; @Autowired(required = false) // 可选依赖 public OrderService(UserService userService) { this.userService = userService; } }
使用 @Resource
java
复制
@Service public class OrderService { private UserService userService; @Resource(required = false) // 错误!@Resource 不支持 required=false public void setUserService(UserService userService) { this.userService = userService; } }
注意:
@Resource
不支持required=false
,需改用其他方式(如@Nullable
或手动检查null
)。
9. 总结
特性 | @Autowired |
@Resource |
---|---|---|
来源 | Spring 特有 | Java 标准(JSR-250) |
匹配方式 | 默认按类型,可用 @Qualifier 按名称 |
默认按名称,也可按类型 |
可选依赖 | 支持(required=false ) |
不支持 |
集合注入 | 支持(List<Bean> /Map<String, Bean> ) |
不支持 |
构造函数注入 | 支持(Spring 4.3+ 可省略注解) | 不支持 |
适用场景 | 纯 Spring 项目 | 跨框架兼容或需要按名称注入 |
推荐实践:
-
优先用
@Autowired
(功能更全面,与 Spring 生态集成更好)。 -
仅在需要跨框架兼容时用
@Resource
(如 Java EE 环境)。 -
按名称注入时:两者均可,但
@Resource
更直观(直接通过name
文章评论