53 归档分页
370 留言互动
4 核心专题

最近更新

日常 2022-06-27

10个词送给不甘平庸的你

作者小邹以“行动、努力、改变、学习、目标、勇气、归零、热爱、宽容、感恩”十个关键词,呼吁不甘平庸的读者及时行动、持续奋斗、主动适应、不断学习、设定并坚持小目标、保持勇气、放下过去、热衷所爱、宽容不完美、常怀感恩,以此在新一年实现自我突破。

Java 2022-06-22

过多赠予,无所适从

本文以 Spring @Autowired 为例,解析“required a single bean, but 2 were found”错误的根源——在容器中存在同类型的多个 Bean,且缺乏 @Primary、@Priority 或名称匹配等优先级标识,导致 Spring 无法决定注入对象。通过源码剖析展示了 Bean 的实例化与属性填充过程以及 AutowiredAnnotationBeanPostProcessor 的工作原理。解决思路包括为其中一个实现加 @Primary、使用 @Qualifier 或通过属性名与 Bean 名称精确匹配等方式,以明确注入目标,进而消除冲突。

Spring编程常见错误 阅读全文
Java 2022-06-21

原型 Bean 被固定

Spring 中把 @Service 标记为原型(@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE))的 Bean 注入到单例 @RestController 的字段时,Autowired 只在容器创建控制器时一次性实例化并固定该对象,导致原型作用失效并出现启动错误。源码分析显示 AutowiredAnnotationBeanPostProcessor 在 populateBean 阶段通过反射把找到的 Bean 直接赋值给字段,后续不再重新获取。解决办法有两种:①注入 ApplicationContext 并在方法中调用 applicationContext.getBean(ServiceImpl.class) 每次获取新实例;②在控制器中声明带 @Lookup 的抽象方法 getServiceImpl(),Spring 利用 CGLIB 生成子类并在调用时从 BeanFactory 动态获取原型 Bean。两种方式均能保证每次请求得到新的 ServiceImpl。文章还解释了 @Lookup 的实现原理以及 Spring 通过反射和方法覆盖实现原型注入的细节,提醒使用者注意单例‑原型混用的潜在陷阱。

Spring编程常见错误 阅读全文
Java 2022-06-21

定义的 Bean 缺少隐式依赖

文章指出,Spring 在创建标记为 @Service(或其他注解)的 Bean 时,如果该类显式声明了构造器,容器会依据构造器参数类型自动在 BeanFactory 中查找对应的 Bean 并注入。若参数(如 String)没有相应的 Bean,Spring 在 AbstractAutowireCapableBeanFactory#createBeanInstance → autowireConstructor → resolveDependency 过程中抛出 “Parameter … could not be found” 异常。解决办法是为构造器参数提供相应的 Bean(如通过 @Bean 定义 String serviceName()),或避免出现多个可选构造器导致歧义。文章提醒开发者不要把 Spring Bean 当作普通对象直接 new,需了解其隐式依赖规则,以免出现装配失败。

Spring编程常见错误 阅读全文
Java 2022-06-20

隐式扫描不到 Bean 的定义

Spring Boot 启动类使用 @SpringBootApplication 时,内部的 @ComponentScan 若未指定 basePackages,会默认扫描启动类所在的包。将 Controller 移到其他包后超出默认扫描范围,导致 Bean 找不到,应用失效。解决办法是显式配置扫描路径,如在启动类上添加 @ComponentScan("com.zou.controller"),或使用 @ComponentScans 指定多个包。需要注意显式指定后默认包不再被扫描,避免遗漏。

Spring编程常见错误 阅读全文
Java 2022-06-13

Java8新特性之Stream流

Stream 是 Java 8 处理集合的核心抽象,提供惰性求值、不可变数据源、可并行执行等特性。文章先介绍了 Stream 的分类(无状态/有状态、短路/非短路),随后列举了五种常用创建方式:Collection 的 stream()/parallelStream()、Arrays.stream、Stream.of/iterate/generate 以及 BufferedReader.lines、Pattern.splitAsStream。接着详细说明了中间操作——filter、limit、skip、distinct、map、flatMap、sorted、peek 等的使用场景和示例。随后阐述了终止操作,包括匹配/查找(allMatch、anyMatch、findFirst 等)、规约(reduce)以及收集(collect),并通过 Collectors 提供的 toList、toSet、toMap、joining、counting、summing、averaging、summarizing 等方法展示了如何将流结果转化为常用容器或统计信息。全文以代码示例为主,帮助读者快速掌握 Stream 的创建、转换、过滤、排序、终止及收集全过程。

JDK Stream 阅读全文