Autowire构造函数被调用两次,甚至在spring中使用了Qualifier



我正在尝试在spring中使用Qualifier学习autowire,并且autowired类构造函数被调用了两次。我有以下课程:

主应用程序:

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();
}

拼写检查器:

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

文本编辑器

public class TextEditor {
@Qualifier("a")
@Autowired
private SpellChecker spellChecker;
public SpellChecker getSpellChecker( ) {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}

我有一个基于java的配置,它有多个具有相同类型的bean,并希望选择一个具有Qualifier的bean,但输出显示构造函数被调用了两次。\

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();
}
}

输出:

Inside SpellChecker constructor.
Inside SpellChecker constructor.
Inside checkSpelling.

由于我使用了限定符("a"(来指定bean,所以我原本希望只调用一个SpellChecker构造函数,但即使我使用限定符来选择sinlge bean,该构造函数也会被调用两次。为什么叫两次??

检出HelloWorldConfig文件。您已经声明了2个类型为SpellChecker:的bean

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

两个bean都是由spring创建的,尽管只有一个bean被注入到TextEditor中。

在spring中,拥有多个相同类型的bean或实现相同接口的bean是完全可以的(想想监听器,它们可能有很多(,因此spring容器将在应用程序启动期间创建所有这些bean。

然而,如果你想将其中一个bean注入另一个bean(在你的例子中是TextEditor(,spring将不知道该注入哪一个,这就是为什么你添加了一个"限定符"特性。

另一个注意事项是,您错误地在配置类上放置了@Component注释,而应该使用@Configuration注释来指定该类包含一系列bean定义(您确实使用@Bean注释声明了这些定义(。尽管"配置"也是一个组件(由spring管理(,但spring仍然以与普通bean明显不同的方式处理它。

还有一点需要注意:虽然这与您的问题没有直接关系,但在您提供的代码片段中,您似乎混合了两种配置风格:带有@Qualifier/@Autowired的风格(如果我没有弄错的话,这种方式是在spring2.5中添加的(和java配置的风格:@Configuration类,其中包含@Bean-s。

您可以完全避免使用autowire,并通过从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;
...
}

现在请注意,您的"业务类"甚至不知道spring——所有的"解析"(限定符和注入规则的使用(都是在spring配置中完成的,无论如何,spring配置都是一个特殊的类。

最新更新