简体   繁体   English

即使在 spring 中使用限定符,也会调用 Autowire 构造函数两次

[英]Autowire constructor is called twice even using Qualifier in spring

I am trying to learn autowire with Qualifier in spring and the autowired class constructor is called twice.我正在尝试使用 spring 中的限定符来学习自动装配,并且自动装配的 class 构造函数被调用了两次。 I have the following class:我有以下 class:

MainApp:主应用:

public class MainApp {
    public static void main(String[] args) {
//        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        ApplicationContext ctx =
                new AnnotationConfigApplicationContext(HelloWorldConfig.class);
//        TextEditor obj = (TextEditor) ctx.getBean("helloWorld");
        TextEditor obj = (TextEditor)ctx.getBean(TextEditor.class);
        obj.spellCheck();

    }

SpellChecker:拼写检查器:

public class SpellChecker {
    public SpellChecker() {
        System.out.println("Inside SpellChecker constructor.");
    }

    public void checkSpelling() {
        System.out.println("Inside checkSpelling.");
    }

TextEditor文本编辑器

public class TextEditor {

    @Qualifier("a")
    @Autowired
    private SpellChecker spellChecker;

    public SpellChecker getSpellChecker( ) {
        return spellChecker;
    }
    public void spellCheck() {
        spellChecker.checkSpelling();
    }
}

I have the java based configuration which has multiple bean with same Type and want to select a single bean with Qualifier but the output shows the constructor is called twice.\我有基于 java 的配置,它有多个具有相同类型的 bean,并且想要 select 一个带有限定符的 bean,但是 output 显示构造函数被调用了两次。

HelloWorldConfig HelloWorldConfig

@Component
public class HelloWorldConfig {
    @Bean
    public HelloWorld helloWorld(){
        return new HelloWorld();
    }
    @Bean
    public TextEditor textEditor(){
        return new TextEditor();
    }
    @Bean(name="a")
    public SpellChecker spellChecker(){
        return new SpellChecker();
    }
    @Bean(name="b")
    public SpellChecker spellChecker1(){
        return new SpellChecker();
    }
}

OUTPUT: OUTPUT:

Inside SpellChecker constructor.
Inside SpellChecker constructor.
Inside checkSpelling.

I was expecting a single SpellChecker constructor call since i used Qualifier("a") to specify the bean, however the constructor is called twice even if I used Qualifier to select a sinlge bean.我期待一个 SpellChecker 构造函数调用,因为我使用 Qualifier("a") 来指定 bean,但是即使我使用 Qualifier 到 select 单个 bean,构造函数也会被调用两次。 Why is it called twice??为什么叫两次??

Check Out HelloWorldConfig file.查看HelloWorldConfig文件。 You've declared 2 beans of type SpellChecker:您已经声明了 2 个 SpellChecker 类型的 bean:

@Bean(name="a")
public SpellChecker spellChecker(){
    return new SpellChecker();
}
@Bean(name="b")    
public SpellChecker spellChecker1(){
   return new SpellChecker();
}

Both beans are created by spring, although only one bean is injected into the TextEditor .这两个 bean 都是由 spring 创建的,尽管只有一个 bean 被注入到TextEditor中。

In spring its perfectly fine to have more than one bean of the same type or beans that implement the same interface (think about listeners - there can be many of them) - so spring container will create them all during the application start.在 spring 中,拥有多个相同类型的 bean 或实现相同接口的 bean 完全没问题(想想监听器 - 可能有很多) - 所以 spring 容器将在应用程序启动期间创建它们。

If you want to inject one of those beans however into another bean (like TextEditor in your case), spring won't have a clue which one to inject, that's why you they've added a "qualifier" feature.但是,如果您想将其中一个 bean 注入另一个 bean(例如您的情况下的TextEditor ), spring 将不知道要注入哪个 bean,这就是您添加“限定符”功能的原因。

Another note, you've by mistake put a @Component annotation on the configuration class, instead you should use @Configuration annotation to specify that this class contains a series of beans definitions (that you indeed declare with @Bean annotation).另请注意,您错误地在配置 class 上放置了@Component注释,而不是您应该使用@Configuration注释来指定此 class 包含一系列 bean 定义(您确实使用@Bean注释声明)。 Although the "configuration" is also a component (managed by spring) - spring still treats it in a significantly different way than regular beans.尽管“配置”也是一个组件(由 spring 管理) - spring 仍然以与普通 bean 截然不同的方式对待它。

And yet another note: although its not directly related to your question, it seems like you're mixing 2 styles of configurations in the code snippet you've provided: the style with @Qualifier/@Autowired (this way was added in spring 2.5 if I'm not mistaken) and the style of java configurations: @Configuration class with @Bean -s in it.还有一个注意事项:虽然它与您的问题没有直接关系,但您似乎在您提供的代码片段中混合了 2 styles 配置: @Qualifier/@Autowired的样式(这种方式已添加到 spring 2.5如果我没记错的话)和 java 配置的风格: @Configuration class 和@Bean -s 在里面。

You can avoid using autowire altogether and inject the dependencies via constructor called from java config like this:您可以完全避免使用自动装配,并通过从 java 配置调用的构造函数注入依赖项,如下所示:

@Configuration
public class HelloWorldConfig {
    @Bean
    public HelloWorld helloWorld(){
        return new HelloWorld();
    }
    @Bean
    public TextEditor textEditor(@Qualifier("a") SpellChecker spellChecker){ // note the dependency here
        return new TextEditor(spellChecker);
    }
    @Bean(name="a")
    public SpellChecker spellChecker(){
        return new SpellChecker();
    }
    @Bean(name="b")
    public SpellChecker spellChecker1(){
        return new SpellChecker();
    }
}

// the TextEditor Class should have a constructor with one argument:

public class TextEditor {
  private final SpellChecker spellChecker;
  public TextEditor(SpellChecker spellChecker) {
     this.spellChecker = spellChecker;
  }
  ...
}

// or if you use lombok library:

@AllArgsConstructor
public class TextEditor {
  private final SpellChecker spellChecker;
  ...
}

Now note, that your "business classes" are not even aware of spring all the "resolution" (usage of qualifier and injection rules) is done in spring configuration which is a special class anyway.现在请注意,您的“业务类”甚至不知道 spring 所有“分辨率”(使用限定符和注入规则)都是在 spring 配置中完成的,无论如何这是一个特殊的 ZA2F2ED4F8EBC2CBB4C21A29DC4。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM