Autowire конструктор вызывается дважды, даже если весной используется Qualifier - PullRequest
0 голосов
/ 26 апреля 2020

Я пытаюсь изучить autowire с Qualifier весной, и конструктор класса autowired вызывается дважды. У меня есть следующий класс:

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

    }

Проверка орфографии:

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

У меня есть конфигурация на основе java, в которой есть несколько компонентов с одним и тем же типом, и я хочу выбрать один компонент с квалификатором, но в выводе показано, что конструктор вызывается дважды. \

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.

Я ожидал одного вызова конструктора SpellChecker, так как я использовал Qualifier ("a") для указания bean, однако конструктор вызывается дважды, даже если я использовал Qualifier для выбора bean-компонента sinlge. Почему это называется дважды ??

1 Ответ

0 голосов
/ 26 апреля 2020

Оформить HelloWorldConfig файл. Вы объявили 2 бина типа SpellChecker:

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

Оба бина создаются весной, хотя в TextEditor.

* 1007 добавляется только один боб. иметь более одного bean-компонента одного типа или bean-компонентов, которые реализуют один и тот же интерфейс (подумайте о слушателях - их может быть много) - поэтому контейнер Spring создаст их все во время запуска приложения.

Если вы хотите Однако, чтобы внедрить один из этих bean-компонентов в другой bean-компонент (например, TextEditor в вашем случае), у Spring не будет подсказки, какой из них вводить, поэтому вы добавили функцию «определителя».

Еще одно замечание: вы по ошибке поместили аннотацию @Component в класс конфигурации, вместо этого вы должны использовать аннотацию @Configuration, чтобы указать, что этот класс содержит серию определений компонентов (которые вы действительно объявляете с помощью аннотации @Bean) , Хотя «конфигурация» также является компонентом (управляемым Spring), Spring по-прежнему обрабатывает его значительно иначе, чем обычные bean-компоненты.

И еще одно замечание: хотя это не имеет прямого отношения к вашему вопросу, кажется, как будто вы смешиваете 2 стиля конфигураций в предоставленном вами фрагменте кода: стиль с @Qualifier/@Autowired (этот способ был добавлен весной 2.5, если я не ошибаюсь) и стиль java конфигураций: @Configuration класс с @Bean -s в нем.

Вы можете полностью отказаться от использования autowire и внедрить зависимости через конструктор, вызываемый из java config следующим образом:

@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, которая в любом случае является специальным классом.

...