Spring Bean配置问题

doMore 393 2024-07-24

问题

使用 @Autowire 自动装配时,注入的类型不是自己想要的类型。

相关资料

Spring中注解自动装配

@Resource 和 @Autowire

@Autowired: 用于构造器、方法、参数或字段上,表明需要自动注入一个Bean。Spring会自动装配匹配的Bean。

@Qualifier: 与@Autowired一起使用时,指定要注入的Bean的名称,以避免与其他Bean混淆。

@Resource: 来自JDK,类似于@Autowired,但默认是按名称装配,也可以混合使用。

@Inject: 来自javax.inject包,类似于@Autowired,属于JSR-330标准的一部分。

@Resource和@Autowired注解区别

@Autowired 是Spring框架提供的注解,主要用于根据类型自动装配依赖项。

行为和特性:

  1. 按类型装配:默认情况下,@Autowired按类型自动装配Bean。

  2. 可选依赖:如果你的依赖是可选的,可以使用required=false设置:

  3. 构造器、方法或字段:可以用在构造器,属性字段或Setter方法上。

  4. 结合@Qualifier:可以和@Qualifier结合使用以实现按名称装配。

  5. 作为Spring特有的注解,它更深度地集成在Spring的生态系统中,更适合与其他Spring注解一起使用。

@Resource 是JDK提供的注解,属于Java依赖注入规范(JSR-250)的一部分。

行为和特性:

  1. 按名称装配:默认情况下,@Resource按名称装配。如果没有匹配到名称,再按类型装配。

  2. 不支持required属性:与@Autowired不同,@Resource不支持required属性。

  3. 可以用于字段和Setter方法:虽然也可以用于构造器,但不常见。通常用在字段或Setter方法上。

  4. 由于是Java EE规范的一部分,它可以与其他Java EE注解(如@PostConstruct和@PreDestroy)更好地配合使用。

Spring依赖注入优先级

使用 @Resource

在使用 @Resource 注解进行依赖注入时,优先级规则如下:

明确指定名称

  • 如果通过 @Resource(name=“beanName”) 明确指定了 Bean 的名称,那么 Spring 会首先按照名称匹配进行注入。

  • 在这种情况下,@Primary 注解不会影响注入结果。

字段或属性名称

  • 如果没有通过 name 属性指定 Bean 的名称,Spring 会尝试按照字段或属性的名称进行匹配。

  • 在这种情况下,@Primary 注解也不会影响注入结果。

类型匹配

  • 如果按名称匹配失败(包括明确指定名称和按字段名称匹配都没有找到合适的 Bean),Spring 会按类型匹配。

  • 在这种情况下,如果存在多个同类型的 Bean,则 @Primary 注解会起作用,标记为 @Primary 的 Bean 将被优先注入。

使用@Autowired

类型匹配

  • Spring 首先通过类型匹配找到所有符合要求的候选 Bean。如果只有一个候选 Bean,那么该 Bean 会被注入。

名称匹配结合 @Qualifier

  • 如果有多个同类型的 Bean,可以使用 @Qualifier 注解来指定具体的 Bean。

  • @Qualifier 的值必须与一个候选 Bean 的名称匹配,匹配成功的 Bean 会被注入。

使用 @Primary

  • 如果仍存在多个符合要求的 Bean,并且其中一个 Bean 标记了 @Primary,Spring 会优先选择标记了 @Primary 的 Bean 进行注入。

名称匹配字段或属性名称

  • 在没有使用 @Qualifier 时,如果存在多个候选 Bean,Spring 会尝试通过字段或属性名称进行匹配。

  • 如果找到名称匹配的 Bean,则该 Bean 会被注入。

NoUniqueBeanDefinitionException:

  • 如果存在多个候选 Bean,但没有使用 @Qualifier 指定名称,且没有标记 @Primary,会抛出 NoUniqueBeanDefinitionException,表明有多个 Bean 类型匹配但无法确定注入哪个。

结论

在使用配置类配置 Bean 时,@Bean 方法的参数,或者用@Autowired配置 Bean 时,最好使用@Qualifier 指定注入的bean,避免注入的bean不符合预期。@Resource 则通常不存在这种烦恼。而且 @Resource 是 JDK 提供,以后如果要迁移到别的框架,也会方便一些。