Понимание использования Spring @Autowired

Я читаю 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;
    }

    // ...
}

как два класса могут быть autowired реализации того же интерфейса и с использованием того же класса?

пример:

class Red implements Color
class Blue implements Color

class myMainClass{
    @Autowired 
    private Color color;

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

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

4 ответов


TL; DR

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

полное описание

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

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

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

на @Autowired аннотация сообщает весне где впрыске нужно произойти. Если вы положите его на метод setMovieFinder понимает (по приставке set + С @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 чтобы сказать, какой из двух цветных бобов вводить:

@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 потому что он не является пружинным и является часть JSR-330 стандартный.
  2. другой хорошей практикой было бы поставить @Inject / @Autowired на конструкторе вместо метода. Если вы поместите его в конструктор, вы можете проверить, что введенные бобы не являются нулевыми и быстро терпят неудачу при попытке запустить приложение и избежать NullPointerException когда вам нужно фактически использовать фасоль.

обновление: в завершите картину, я создал новому вопросу о @Configuration класса.


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

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

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

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

этот autowiring потерпит неудачу:

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

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

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

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

после того, как у вас настроена Весна, вероятно, вы можете сделать следующее В файле xml контекста сервлета Spring, например 1 выше, чтобы работать (пожалуйста заменить имя пакета com.кино к чему истинное имя пакета и если это класс 3rd party, то убедитесь, что соответствующий файл 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>

...где?!--6-->otherBeanRef ' - еще один боб, который имеет ссылку на ожидаемый класс.


@Autowired

пусть Spring автоматически подключает другие бобы в ваши классы, используя аннотацию @Autowired.

@Service
public class CompanyServiceImpl implements CompanyService {

    @Autowired
    private CompanyDAO companyDAO;

    ...
}

весенние аннотации Совет весенние бобы могут быть подключены по имени или по типу. @Autowire по умолчанию является инъекцией, управляемой типом. @ Qualifier spring аннотация может быть использована для дальнейшей тонкой настройки autowiring. @Resource (javax.аннотация.Ресурс) аннотация может использоваться для проводки по названию. Бобы, которые сами определены как коллекция или тип карты, не могут быть вводится через @Autowired, потому что сопоставление типов неправильно применимо к ним. Используйте @Resource для таких бобов, ссылаясь на конкретную коллекцию или карту бобов по уникальному имени