文章介绍了 Spring 中 @Autowired 注入时出现 “required a single bean, but 2 were found” 的常见错误。通过一个学生管理系统的示例,展示当同一接口有多个实现(如 Oracle 与 Cassandra 数据服务)时,Spring 在自动装配过程中无法确定唯一候选 Bean,导致启动失败。文中解析了 @Autowired 的底层实现流程,说明候选 Bean 的优先级由 @Primary、@Priority 或 Bean 名称匹配决定,并指出默认 required 为 true 时必须唯一。针对问题,提供了三种解决思路:①在其中一个实现上加 @Primary;②使用 @Qualifier 或属性名与 Bean 名称精确匹配;③将依赖改为集合、数组等可接受多 Bean 的类型。最后强调选择方案需符合业务需求,避免随意覆盖实现。

案例展示了在 Spring 中把原型 Bean(@Scope(PROTOTYPE))直接 @Autowired 到单例 Controller 时,属性只在首次注入后被固定,导致原型特性失效并报错。分析源码发现 Autowired 只在 Bean 创建时一次性通过反射注入,后续不会重新获取实例。解决办法有两种:① 注入 ApplicationContext,在使用时通过 applicationContext.getBean(ServiceImpl.class) 手动获取新实例;② 在 Controller 中声明 @Lookup 标记的方法,Spring 会生成 CGLIB 子类并在每次调用时从 BeanFactory 取回新的原型 Bean,方法体代码甚至可以为 null。文章还简要说明了 @Lookup 的实现原理及 Spring 反射注入的潜规则,提醒开发者在单例中使用原型时必须采用动态获取方式。

在 Spring 中,标记为 `@Service` 的类会被注册为 Bean。若该类显式声明构造器,Spring 在实例化时会自动根据构造器参数去容器中查找同类型的 Bean 并注入。示例 `ServiceImpl(String serviceName)` 因容器中没有 `String` 类型的 Bean,导致启动时报 “required a bean of type 'java.lang.String' that could not be found”。源码 `AbstractAutowireCapableBeanFactory#createBeanInstance` → `autowireConstructor` → `resolveDependency` 体现了这一流程。解决办法是显式声明相应的 Bean,例如 `@Bean public String serviceName(){ return "MyServiceName"; }`。此外,若同一类存在多个构造器且都可匹配,Spring 将无法确定使用哪一个,进而报错。因此在定义 Bean 时需遵循 Spring 的隐式依赖规则,避免把普通类当作可直接 `new` 的对象使用。

Spring Boot 启动类使用 @SpringBootApplication 时,内部的 @ComponentScan 若未指定 basePackages,默认只扫描启动类所在包。将 Controller 移到其它包后,Spring 找不到其 Bean,导致接口失效。解决办法是显式配置扫描路径,例如在启动类上添加 `@ComponentScan("com.zou.controller")`,或使用 `@ComponentScans` 指定多个包。需注意,一旦显式指定,默认包不会再被自动扫描。

Stream 是 Java 8 处理集合的核心抽象,提供惰性求值、无副作用的操作链,可顺序或并行执行。它不保存数据,也不修改源集合,而是通过中间操作(filter、limit、skip、distinct、map、flatMap、sorted、peek 等)记录转换步骤,待终止操作(allMatch、anyMatch、noneMatch、findFirst、findAny、count、max、min、reduce、collect)触发实际计算。Stream 可通过 Collection、数组、Stream 静态方法、BufferedReader、Pattern 等多种方式创建。终止操作中的 reduce 支持标识值、累加器和合并器,parallelStream 时合并器用于跨线程合并结果。collect 结合 Collector 接口和 Collectors 工具类,可将流元素收集为 List、Set、Map,或执行计数、求和、平均、最大最小等聚合统计。整体上,Stream API 让集合处理更像 SQL 查询,代码更简洁、可读且易于并行化。

本文概述了 Java 17 作为 LTS 版本在语法层面的重要更新,重点包括文本块(多行字符串)、带返回值的 switch 表达式、简洁的 record 数据类、可限制子类的 sealed class、instanceof 模式匹配、更加友好的 NullPointerException 信息、日期周期与紧凑数字的格式化以及 Stream.toList() 简化集合转化。通过代码示例展示了这些特性如何提升可读性、减少样板代码并帮助开发者更高效地定位错误。