加载中

Spring编程常见错误

文章分类

浏览该分类下的所有文章

4 篇文章 1

过多赠予,无所适从

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

原型 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 通过反射和方法覆盖实现原型注入的细节,提醒使用者注意单例‑原型混用的潜在陷阱。

定义的 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,需了解其隐式依赖规则,以免出现装配失败。

隐式扫描不到 Bean 的定义

Spring Boot 启动类使用 @SpringBootApplication 时,会自动开启 @ComponentScan,默认只扫描启动类所在包及其子包。将 Controller 移至其他包后,因未在扫描范围内,Spring 无法注册 HelloWorldController 为 Bean,导致接口失效。解决办法是显式指定扫描路径,例如在启动类上添加 @ComponentScan("com.zou.controller"),或使用 @ComponentScans 组合多个包。需要注意,显式配置后默认包不再自动扫描,须自行包含所有需要的包。