【问题标题】:Spring bean with same method name but different qualifier fail to load具有相同方法名称但不同限定符的 Spring bean 无法加载
【发布时间】:2019-02-16 20:01:41
【问题描述】:

我有两个 Spring Configuration 类定义如下

@Configuration
public class ClsA {

     @Bean
      @Qualifier("ClasA")
      public String getSomething(){
         return "somethingA";
     }
}


@Configuration
public class ClsB {

     @Bean
      @Qualifier("ClsB")
      public String getSomething(){
         return "somethingB";
     }
}

两者具有相同的方法名称。即使限定符不同,应用程序也不会加载,因为它只注入一个,并且无论在哪里注入另一个,如果因 noBeanDefinition 异常而失败,假设为 ClsB bean 限定符。

当我保持方法名称不同并且所有内容都加载时。

这种行为正常吗?为什么 spring 不能很好地加载这些 bean,因为它们有不同的限定符?

【问题讨论】:

    标签: spring


    【解决方案1】:

    @Qualifier 注释应该用于resolve ambiguity 的注入点,以确定注入哪个 bean。但在示例中,您在 bean 声明站点使用它。在声明站点,您可以通过在 @Bean 注释中指定每个 bean 来为每个 bean 命名。因此,如果您使用相同的名称保留方法,则有效示例如下:

    @Configuration
    public class ClsA {
        @Bean("ClasA")
        public String getSomething() {
            return "somethingA";
        }
    }
    
    @Configuration
    public class ClsB {
        @Bean("ClasB")
        public String getSomething() {
            return "somethingB";
        }
    }
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {ClsB.class, ClsA.class})
    public class ClsTest {
        @Autowired
        @Qualifier("ClasA") //this is the place where @Qualifier can be used
        String smthA;
    
        @Autowired
        @Qualifier("ClasB")
        String smthB;
    
        @Test
        public void test() {
            System.out.println(smthA);
            System.out.println(smthB);
        }
    }
    

    输出:

    somethingA
    somethingB
    

    【讨论】:

    • 谢谢。 @Bean("ClasB") 和@Bean(name="ClasB") 之间有什么区别吗?此外,在我的情况下,我在注入点使用 Qualifier 注释按 bean 名称注入。那么我应该使用 Resource 还是 Autowired 注入,还是都一样?
    • @Bean("ClasB")@Bean(name="ClasB")valuename 属性的语义相同,相互之间是 aliases
    • @Autowired vs @Resource 主题不适合评论。简而言之,它们在注入匹配过程中具有不同的顺序,如绿色注释中的official doc 中所述。 @Autowired 按类型和限定符,@Resource 按名称。此外,@Autowired 可以应用于字段、构造函数和多参数方法。但是,在您的特定情况下,@Resource@Autowired 之间没有太大区别
    【解决方案2】:

    1。自定义 Bean 命名

    每个 bean 名称必须是唯一的。

    @Configuration
    public class ClsA {
    
        @Bean("clasAText")
        public String getSomething() {
            return "somethingA";
        }
    }
    
    @Configuration
    public class ClsB {
    
        @Bean("clsBText")
        public String getSomething() {
            return "somethingB";
        }
    }
    

    2。 (可选)添加限定符元数据

    @Configuration
    public class ClsA {
    
        @Bean("clasAText")
        @Qualifier("clsA")
        public String getSomething() {
            return "somethingA";
        }
    }
    
    @Configuration
    public class ClsB {
    
        @Bean("clsBText")
        @Qualifier("clsB")
        public String getSomething() {
            return "somethingB";
        }
    }
    

    3-1。按名称注入

    @Component
    public class MyComponent {
    
        @Resource(name = "clasAText")
        private String text;
    
        // ...
    }
    

    Note:

    如果您打算通过名称来表达注解驱动的注入,请不要主要使用@Autowired (snip)。而是使用 JSR-250 @Resource 注释

    3-2。通过限定符注入

    如果添加了限定符,则这些是可用的。

    @Component
    public class MyComponent {
    
        @Autowired
        @Qualifier("clsA")
        private String text;
    
        // ...
    }
    

    This answer 是一种后备行为。名称和限定符是不同的。

    对于后备匹配,bean 名称被视为默认限定符值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      相关资源
      最近更新 更多