依赖解析的核心是:先确定注入点需要什么,再从候选 Bean 中选出唯一结果。候选不唯一时,Spring 不会靠“碰巧的注册顺序”静默选择。
Table of contents
Open Table of contents
运行 Primary 选择实验
TimeGreetingPort下载使用 @Primary 表示同类型候选中的默认实现:
mvn -Dtest=SpringSourceLabTest#springResolvesPrimaryConstructorDependency test
测试上下文注册两个 GreetingPort,容器把带 @Primary 的实现注入 GreetingService。
Spring 怎样选择构造器
只有一个构造器时,不需要写 @Autowired。存在多个构造器时,明确标注可注入构造器,或确保选择规则无歧义。为了读者和测试清晰,业务类通常只保留一个表达必需依赖的构造器。
解析每个参数时,Spring考虑类型、泛型、Qualifier、Primary、Fallback、优先级和注入点名称。参数名只应作为最后的消歧义线索,不应代替显式业务语义。
Primary 与 Qualifier 的职责
@Primary 表示全局默认候选;@Qualifier("billing") 表示该注入点需要某个语义分组。若不同调用方需要不同实现,Qualifier 比不断切换 Primary 更清楚。
注入 List<Handler> 会获得全部匹配 Bean,并按 @Order 或 Ordered 排序。注入 ObjectProvider<T> 可以延迟获取或迭代候选,但不要用它把 Service Locator 模式重新带回核心业务。
Optional 不应隐藏必需配置
Optional<T>、ObjectProvider<T> 或 @Autowired(required=false) 适合真正可选的扩展。支付客户端、数据源等必需能力缺失时,应让启动失败,而不是运行到第一笔请求才报空指针。
诊断 NoUniqueBeanDefinitionException 时列出所有候选及其来源配置;诊断 NoSuchBeanDefinitionException 时检查扫描范围、条件装配报告和泛型是否匹配。
下一步
阅读三级缓存能解决什么循环依赖,区分可暴露早期引用的属性循环和无法成立的构造器循环。