本文以 Spring @Autowired 常见的 “required a single bean, but 2 were found” 错误为例,先展示在学生管理系统中因新增 CassandraDataService 实现而导致的启动异常。随后深入剖析 @Autowired 的注入流程,说明 Spring 在解析依赖时会在所有同类型 Bean 中寻找唯一候选,决定依据包括 @Primary、@Priority 以及 Bean 名称的严格匹配,若无可比优先级且属性不可接受多 Bean(如非集合、数组),便抛出冲突异常。针对该问题,提供三类解决思路:①在需要的实现上加 @Primary;②使用 @Qualifier 或属性名与 Bean 名称相同实现显式匹配;③将依赖改为集合、Map 等可接受多 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 时,会依据其构造函数的参数从容器中查找对应的依赖并通过反射实例化。如果构造函数需要的类型(如 String)在容器中不存在,Spring 在创建 Bean 时就会抛出 “required a bean of type … could not be found” 的错误。源码显示,Spring 通过 resolveDependency 在 BeanFactory 中寻找匹配的 Bean,并将其组装为构造参数。解决办法是显式在配置中提供所需的 Bean(如 `@Bean public String serviceName(){ return "MyServiceName"; }`),或避免多个可选构造函数导致歧义。文章提醒开发者不要用普通 new 方式思考 Bean 的创建,必须遵循 Spring 的隐式依赖装配规则。

Spring Boot 启动类使用 @SpringBootApplication,内部含有默认的 @ComponentScan。若不指定 basePackages,扫描范围仅是启动类所在的包(本例的 com.zou.application),因此把 Controller 移到别的包后 Spring 找不到其 Bean,导致接口失效。源码解析显示,当 basePackages 为空时会以声明类的包为基准进行扫描。解决办法是显式声明扫描路径,例如在启动类上加 @ComponentScan("com.zou.controller"),或使用 @ComponentScans 指定多个包。需要注意,显式指定后默认包会被覆盖,需自行加入所有需要的包。

Stream是Java 8用于集合处理的抽象概念,提供惰性求值、不会修改源数据、可并行执行等特性。根据是否依赖前元素分为有状态/无状态、是否可短路分为短路/非短路。流可通过Collection、数组、Stream.of/iterate/generate、BufferedReader.lines、Pattern.splitAsStream等方式创建。中间操作包括filter、limit、skip、distinct、map、flatMap、sorted、peek等,用于过滤、切片、映射、排序和调试。终止操作分为匹配/查找(allMatch、anyMatch、findFirst 等)、规约(reduce)和收集(collect),后者结合Collectors 可生成List、Set、Map、字符串拼接以及统计信息(count、sum、average、summary)。全文通过代码示例展示了这些API 的使用方法及并行流的行为差异。

Java 17是自Java 11后的又一个 LTS 版本,本文重点介绍其语法层面的九大改进,并配以代码示例帮助理解。通过文本块(""")简化多行字符串;switch 表达式支持返回值、箭头语法和 yield,避免显式 break;record 关键字提供简洁的不可变数据类;sealed class 让超类限定子类集合,实现更细粒度的继承控制;instanceof 模式匹配把类型检查、强转和变量声明合并;Helpful NullPointerExceptions 在空指针异常中直接指出导致 NPE 的具体调用;新增日期周期格式化、紧凑数字格式化以及 Stream.toList() 方法,使代码更简洁、可读性更高。