Spring依赖注入与Java规范详解
一、@Autowired和@Resource注解比较
1.1 基本区别
| 特性 | @Autowired | @Resource |
| ——– | ——————————————– | ————————————– |
| 来源 | Spring框架 | JSR-250规范 |
| 包名 | org.springframework.beans.factory.annotation | javax.annotation |
| 注入方式 | 默认按类型(byType) | 默认按名称(byName),名称未指定时按类型 |
| 解决冲突 | 需结合@Qualifier使用 | 直接通过name属性指定 |
| 其他特性 | 有required属性可设置非必须依赖 | 具有更好的可移植性 |
| 使用位置 | 构造函数、字段、方法、参数 | 字段、方法 |
1.2 使用示例
@Autowired使用示例:
// 按类型注入
@Autowired
private UserService userService;
// 配合@Qualifier解决多个相同类型bean的冲突
@Autowired
@Qualifier("mysqlUserDao")
private UserDao userDao;
// 设置为非必须依赖
@Autowired(required = false)
private OptionalService optionalService;
@Resource使用示例:
// 默认按名称注入
@Resource
private UserService userService;
// 明确指定名称
@Resource(name = "mysqlUserDao")
private UserDao userDao;
二、JSR规范概述
2.1 JSR基本概念
- 定义:JSR(Java Specification Request,Java规范提案)是为Java平台添加新特性和技术的正式规范文档
- 目的:确保Java技术的标准化、兼容性和可移植性
- 组织方式:由JCP(Java Community Process,Java社区进程)管理,专家组负责规范的制定和审核
- 生命周期:提案→早期草案→公开审阅→最终发布→维护
2.2 JSR的重要性
- 标准化:为Java技术提供统一标准,避免技术碎片化
- 兼容性:确保不同厂商的Java实现能够相互兼容
- 开放性:允许社区参与Java平台的发展和演进
- 技术发展:推动Java技术的创新和进步
2.3 重要的JSR规范示例
- JSR-175:Java注解(Annotations)规范
- JSR-250:Common Annotations(包含@Resource等注解)
- JSR-303/JSR-349:Bean Validation规范
- JSR-330:依赖注入标准规范(@Inject等)
- JSR-317/JSR-338:JPA(Java Persistence API)规范
- JSR-365:CDI(Contexts and Dependency Injection)规范
- JSR-370:JAX-RS(Java API for RESTful Web Services)
三、@Resource注解与JSR-250规范
3.1 JSR-250规范概述
- 名称:Common Annotations for the Java Platform(Java平台通用注解)
- 目的:为Java SE和Java EE平台开发一系列通用语义概念的注解,这些注解适用于多种技术
- 初始版本:JSR-250在Java EE 5中首次引入
- 当前版本:目前最新版本为1.2版
- 现状:现已成为Jakarta EE项目的一部分,重命名为Jakarta Annotations
3.2 JSR-250中的主要注解
JSR-250规范不仅定义了@Resource注解,还定义了其他几个重要的通用注解:
- @Resource:用于资源注入
- @PostConstruct:标记实例构造后要调用的方法
- @PreDestroy:标记实例销毁前要调用的方法
- @Resources:用于声明多个@Resource注解
- @Generated:标记由工具生成的源代码
- @RunAs:安全角色相关
- @DeclareRoles:声明安全角色
- @RolesAllowed:访问控制注解
- @PermitAll:允许所有角色访问
- @DenyAll:拒绝所有角色访问
3.3 @Resource注解用途
@Resource注解主要用于将各种类型的资源注入到Java类中,包括:
- 数据源(DataSource)
- JMS连接工厂和目的地
- 环境条目
- EJB引用
- Web服务引用等
它在企业应用中广泛用于依赖注入,特别是在Java EE环境中。
3.4 在Java EE和Spring中的应用
- 在Java EE环境中,@Resource是标准的资源注入方式
- 在Spring框架中,虽然有自己的@Autowired注解,但Spring也支持JSR-250规范中的@Resource注解,这体现了Spring对Java标准的兼容性
四、@Autowired注入优先级详解
4.1 基本注入优先级规则
@Autowired 注入遵循以下优先级顺序:
- 按类型匹配(默认行为)
- 使用 @Qualifier 指定名称
- 使用 @Primary 标记首选 bean
- 变量名称与 bean 名称匹配
- 构造器 > 方法 > 字段 (注入点优先级)
4.2 按类型注入详解
当使用 @Autowired 且不指定任何额外条件时,Spring 首先尝试按类型匹配:
@Service
public class UserService {
@Autowired
private UserRepository userRepository; // 寻找类型为 UserRepository 的 bean
}
如果容器中只有一个 UserRepository 类型的 bean,则直接注入。
4.3 多个同类型 bean 的处理
当容器中存在多个相同类型的 bean 时,Spring 按以下顺序解决冲突:
4.3.1 @Primary 注解优先
@Repository
@Primary
public class MySQLUserRepository implements UserRepository {
// 实现...
}
@Repository
public class MongoUserRepository implements UserRepository {
// 实现...
}
此例中,自动注入时 MySQLUserRepository 将被优先选择。
4.3.2 @Qualifier 指定名称
@Qualifier 具有比 @Primary 更高的优先级:
@Repository("mongoRepo")
public class MongoUserRepository implements UserRepository {}
@Repository
@Primary
public class MySQLUserRepository implements UserRepository {}
@Service
public class UserService {
@Autowired
@Qualifier("mongoRepo")
private UserRepository userRepository; // 将注入 MongoUserRepository
}
4.3.3 变量名匹配
当没有 @Qualifier 和 @Primary 时,变量名与 bean 名称匹配:
@Repository
public class MySQLUserRepository implements UserRepository {}
@Repository
public class MongoUserRepository implements UserRepository {}
@Service
public class UserService {
@Autowired
private UserRepository mongoUserRepository; // 将注入 MongoUserRepository
}
4.4 注入点优先级
Spring 在处理同一个类中多个注入点时的优先级顺序:
- 构造器注入:最高优先级,推荐用于必需依赖
- setter 方法注入:次优先级
- 字段注入:最低优先级
@Service
public class ComplexService {
private final MainRepository mainRepository;
@Autowired // 构造器注入优先执行
public ComplexService(MainRepository mainRepository) {
this.mainRepository = mainRepository;
}
@Autowired // 其次执行方法注入
public void setHelper(HelperService helperService) {
this.helperService = helperService;
}
@Autowired // 最后执行字段注入
private OptionalService optionalService;
}
4.5 集合与数组注入
当字段类型为集合或数组时,Spring 会收集所有匹配类型的 bean:
@Service
public class AggregateService {
@Autowired
private List<PaymentProcessor> processors; // 注入所有 PaymentProcessor 类型的 bean
@Autowired
private Map<String, PaymentProcessor> processorMap; // 注入所有 PaymentProcessor 以bean名为key
}
4.6 实际应用建议
- 优先使用构造器注入:使依赖关系明确且不可变
- 对必需依赖使用 final 字段:防止依赖被修改
- 对可选依赖使用 @Autowired(required=false):避免找不到 bean 时抛出异常
- 在有多个同类型 bean 时使用明确的 @Qualifier:提高代码可读性和可维护性
- 慎用 @Primary:可能在大型项目中导致意外行为
五、Spring框架与JSR规范的关系
Spring框架实现了许多JSR规范,如:
- 依赖注入规范(JSR-330)
- Common Annotations(JSR-250,包括@Resource注解)
- Bean Validation(JSR-303)
同时,Spring也提供了自己的扩展和实现,比如@Autowired注解,以提供更加丰富和灵活的功能。Spring框架的设计理念是尽可能地与Java标准兼容,同时提供更强大的功能和更好的开发体验。