Понимание Spring @Пользовательское использование

Я читаю справочную документацию весны 3.0.x, чтобы понять аннотацию Spring Autowired:

3.9.2 @Autowired и @Inject

Я не могу понять приведенные ниже примеры. Нужно ли нам что-то делать в XML, чтобы он работал?

ПРИМЕР 1

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

ПРИМЕР 2

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog,
                    CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

Как можно использовать два класса для реализации одного и того же интерфейса и использования одного и того же класса?

Пример:

class Red implements Color
class Blue implements Color

class myMainClass{
    @Autowired 
    private Color color;

    draw(){
        color.design(); 
    } 
}

Какой метод проектирования будет называться? Как я могу убедиться, что метод проектирования класса Red будет вызываться, а не Blue?

+243
источник поделиться
4 ответа

TL; DR

Аннотации @Autowired избавляют вас от необходимости прокладывать проводку самостоятельно в файле XML (или любым другим способом) и просто находят для вас, что нужно вводить туда, где и что вы делаете для вас.

Полное объяснение

@Autowired аннотация позволяет пропустить конфигурации в другом месте, что нужно вводить, и просто делает это для вас. Предполагая, что ваш пакет com.mycompany.movies вы должны поместить этот тег в свой XML файл (контекстный файл приложения):

<context:component-scan base-package="com.mycompany.movies" />

Этот тег будет выполнять автоматическое сканирование. Предполагая, что каждый класс, который должен стать bean-компонентом, аннотируется с помощью правильной аннотации, такой как @Component (для простого компонента) или @Controller (для управления сервлетом) или @Repository (для классов DAO), и эти классы находятся где-то под пакетом com.mycompany.movies, Spring найдет все это и создаст компонент для каждого из них. Это делается при 2-х проверках классов - в первый раз, когда он просто ищет классы, которые должны стать компонентом, и отображает инъекции, которые он должен выполнять, а на втором сканировании он вводит компоненты. Конечно, вы можете определить свои компоненты в более традиционном XML файле или в классе @Configuration (или любой комбинации из трех).

@Autowired сообщает Spring, где должна произойти инъекция. Если вы положили его на метод setMovieFinder он понимает (по set префикса + @Autowired annotation), что необходимо @Autowired компонент. Во втором сканировании Spring ищет компонент типа MovieFinder, и если он находит такой компонент, он вводит его в этот метод. Если он найдет два таких компонента, вы получите Exception. Чтобы избежать Exception, вы можете использовать аннотацию @Qualifier и указать, какой из двух компонентов будет вводить следующим образом:

@Qualifier("redBean")
class Red implements Color {
   // Class code here
}

@Qualifier("blueBean")
class Blue implements Color {
   // Class code here
}

Или, если вы предпочитаете объявлять компоненты в своем XML, это выглядит примерно так:

<bean id="redBean" class="com.mycompany.movies.Red"/>

<bean id="blueBean" class="com.mycompany.movies.Blue"/>

В объявлении @Autowired вам нужно также добавить @Qualifier чтобы указать, какая из двух цветовых @Qualifier для инъекции:

@Autowired
@Qualifier("redBean")
public void setColor(Color color) {
  this.color = color;
}

Если вы не хотите использовать две аннотации (@Autowired и @Qualifier), вы можете использовать @Resource для объединения этих двух:

@Resource(name="redBean")
public void setColor(Color color) {
  this.color = color;
}

@Resource (вы можете прочитать некоторые дополнительные данные об этом в первом комментарии к этому ответу) избавляет вас от использования двух аннотаций, и вместо этого вы используете только один.

Я просто добавлю еще два комментария:

  1. Хорошей практикой было бы использовать @Inject вместо @Autowired потому что он не зависит от Spring и является частью стандарта JSR-330.
  2. Другой хорошей практикой было бы поставить @Inject/@Autowired на конструктор вместо метода. Если вы поместите его в конструктор, вы можете проверить, что введенные bean-компоненты не являются нулевыми и не работают быстро, когда вы пытаетесь запустить приложение и избегаете исключения NullPointerException когда вам нужно фактически использовать компонент.

Обновление. Чтобы завершить изображение, я создал новый вопрос о классе @Configuration.

+470
источник

Ничто в этом примере не говорит о том, что "классы реализуют один и тот же интерфейс". MovieCatalog - тип, а CustomerPreferenceDao - другой тип. Spring могут легко отличить их друг от друга.

В Spring 2.x проводка beans в основном произошла с помощью идентификаторов или имен bean. Это все еще поддерживается Spring 3.x, но часто у вас будет один экземпляр bean с определенным типом - большинство служб - это одиночные. Создание имен для них утомительно. Итак, Spring начал поддерживать "autowire by type".

В примерах показаны различные способы, которые вы можете использовать для ввода beans в поля, методы и конструкторы.

XML уже содержит всю информацию, необходимую Spring, поскольку вам нужно указать полное имя класса в каждом bean. Однако вам нужно быть немного осторожным с интерфейсами:

Это автоматическое завершение не будет выполнено:

 @Autowired
 public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }

Так как Java не сохраняет имена параметров в байтовом коде, Spring больше не может различать два beans. Исправление состоит в использовании @Qualifier:

 @Autowired
 public void prepare( @Qualifier("bean1") Interface1 bean1,
     @Qualifier("bean2")  Interface1 bean2 ) { ... }
+16
источник
другие ответы

Связанные вопросы


Похожие вопросы

Да, вы можете настроить XML файл Spring сервлета контекста, чтобы определить ваш beans (т.е. классы), чтобы он мог выполнить автоматическую инъекцию для вас. Однако имейте в виду, что вам нужно делать другие конфигурации, чтобы работать с Spring и лучший способ сделать это, - это следовать за учебником.

Как только у вас будет настроен ваш Spring, вы можете сделать следующее в вашем xml файле контекста сервлета Spring для примера 1 выше, чтобы работать (пожалуйста, замените имя пакета com.movies к тому, что истинное имя пакета и если это сторонний класс, тогда убедитесь, что соответствующий файл jar находится в пути к классам):

<beans:bean id="movieFinder" class="com.movies.MovieFinder" />

или если класс MovieFinder имеет конструктор с примитивным значением, то вы могли бы что-то вроде этого,

<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
    <beans:constructor-arg value="100" />
</beans:bean>

или если класс MovieFinder имеет конструктор, ожидающий другого класса, тогда вы можете сделать что-то вроде этого,

<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
    <beans:constructor-arg ref="otherBeanRef" />
</beans:bean>

... где "otherBeanRef" - ​​это еще один bean, который ссылается на ожидаемый класс.

+5
источник

@Autowired

Пусть Spring автоматически подключит другие beans к вашим классам с помощью @Autowired аннотации.

@Service
public class CompanyServiceImpl implements CompanyService {

    @Autowired
    private CompanyDAO companyDAO;

    ...
}

Spring Конспект аннотации Spring beans может быть связан по имени или по типу. @Autowire по умолчанию является инъекцией типа. Аннотацию @Qualifier Spring можно использовать для дальнейшей тонкой настройки автоподготовки. Аннотацию @Resource (javax.annotation.Resource) можно использовать для проводки по имени. Beans, которые сами по себе определяются как тип коллекции или карты, не могут быть введены через @Autowired, поскольку сопоставление типов не относится к ним надлежащим образом. Используйте @Resource для такого beans, ссылаясь на конкретную коллекцию или карту bean по уникальному имени

+5
источник

Посмотрите другие вопросы по меткам или Задайте вопрос