Аннотация @Inject
по стандарту JSR 330 может быть использована вместо аннотации @Autowired
из Spring в примерах, включенных в этот раздел.
Вы можете применить аннотацию @Autowired
к конструкторам, как показано в следующем примере:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
class MovieRecommender @Autowired constructor(
private val customerPreferenceDao: CustomerPreferenceDao)
Начиная со Spring Framework 4.3, аннотация @Autowired
для такого конструктора больше не нужна, если целевой бин сперва определяет только один конструктор. Однако, если доступно несколько конструкторов и нет основного конструктора по умолчанию, хотя бы один из них должен быть аннотирован @Autowired
, чтобы предоставить контейнеру инструкцию, какой из них использовать.
Вы также можете применить аннотацию @Autowired
к традиционным сеттерам, как показано в следующем примере:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
class SimpleMovieLister {
@set:Autowired
lateinit var movieFinder: MovieFinder
// ...
}
Вы также можете применить аннотацию к методам с произвольными именами и несколькими аргументами, как показано в следующем примере:
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
class MovieRecommender {
private lateinit var movieCatalog: MovieCatalog
private lateinit var customerPreferenceDao: CustomerPreferenceDao
@Autowired
fun prepare(movieCatalog: MovieCatalog,
customerPreferenceDao: CustomerPreferenceDao) {
this.movieCatalog = movieCatalog
this.customerPreferenceDao = customerPreferenceDao
}
// ...
}
Вы можете применять @Autowired
и к полям, и даже смешивать его с конструкторами, как показано в следующем примере:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
private MovieCatalog movieCatalog;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
class MovieRecommender @Autowired constructor(
private val customerPreferenceDao: CustomerPreferenceDao) {
@Autowired
private lateinit var movieCatalog: MovieCatalog
// ...
}
Убедитесь, что ваши целевые компоненты (например, MovieCatalog
или CustomerPreferenceDao
) последовательно объявлены типом, который вы используете для точек внедрения, аннотированных с помощью @Autowired
. В противном случае внедрение может завершиться ошибкой "соответствие типов не найдено" во время выполнения.
Для бинов, определенных на основе XML, или классов компонентов, найденных с помощью сканирования пути класса (classpath), контейнер обычно заранее знает конкретный тип. Однако для фабричных методов @Bean
необходимо убедиться, что объявленный тип возврата достаточно выразителен. Для компонентов, реализующих несколько интерфейсов, или для компонентов, на которые потенциально можно ссылаться по типу их реализации, рассмотрите возможность объявления наиболее специфичного возвращаемого типа для вашего фабричного метода (по крайней мере, настолько специфичного, насколько это требуется точкам внедрения, ссылающимися на ваш бин).
Вы также можете дать Spring команду предоставить все бины определенного типа из ApplicationContext
, добавив аннотацию @Autowired
к полю или методу, который ожидает массив этого типа, как показано в следующем примере:
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}
class MovieRecommender {
@Autowired
private lateinit var movieCatalogs: Array<MovieCatalog>
// ...
}
То же самое относится и к типизированным коллекциям, как показано в следующем примере:
public class MovieRecommender {
private Set<MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
class MovieRecommender {
@Autowired
lateinit var movieCatalogs: Set<MovieCatalog>
// ...
}
Ваши целевые бины могут реализовать интерфейс org.springframework.core.Ordered
или использовать аннотацию @Order
или стандартную аннотацию @Priority
, если вам нужно, чтобы элементы в массиве или списке были отсортированы в определенном порядке. В противном случае их порядок следует порядку регистрации соответствующих определений целевых бинов в контейнере.
Вы можете объявить аннотацию @Order
на уровне целевого класса и на уровне методов @Bean
потенциально для отдельных определений бинов (в случае нескольких определений, использующих один и тот же класс бинов). Значения @Order
могут влиять на приоритеты в точках внедрения, но имейте в виду, что они не влияют на порядок запуска объектов-одиночек, который является ортогональной функцией, определяемой отношениями зависимости и объявлениями @DependsOn
.
Обратите внимание, что стандартная аннотация javax.annotation.Priority
недоступна на уровне @Bean
, поскольку она не может быть объявлена для методов. Её семантика может быть смоделирована через значения @Order
в сочетании с @Primary
на одном бине для каждого типа.
Даже типизированные экземпляры Map
могут быть автоматически найдены и связаны, если ожидаемый тип ключа - String
. Значения в ассоциативных массивах (maps) содержат все бины ожидаемого типа, а ключи - соответствующие имена бинов, как показано в следующем примере:
public class MovieRecommender {
private Map<String, MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
class MovieRecommender {
@Autowired
lateinit var movieCatalogs: Map<String, MovieCatalog>
// ...
}
По умолчанию автоматический поиск и связывание не работает, если для данной точки внедрения нет подходящих бинов-кандидатов. В случае объявленного массива, коллекции или ассоциативного массива ожидается наличие хотя бы одного совпадающего элемента.
Логика работы по умолчанию - рассмотрение аннотированных методов и полей как указывающих на необходимые зависимости. Вы можете изменить эту логику, как показано в следующем примере, позволяя фреймворку пропускать точку внедрения, не удовлетворяющую условиям, пометив ее как необязательную (т.е. установив атрибут required
в @Autowired
как false
):
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired(required = false)
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
class SimpleMovieLister {
@Autowired(required = false)
var movieFinder: MovieFinder? = null
// ...
}
Необязательный метод не будет вызван вообще, если его зависимость (или одна из зависимостей в случае нескольких аргументов) недоступна. Необязательное поле в таких случаях вообще не заполняется, оставляя значение по умолчанию.
Аргументы внедренного конструктора и фабричного метода являются особым случаем, поскольку атрибут required
в @Autowired
имеет несколько иное значение из-за алгоритма разрешения конструктора Spring, который потенциально может работать с несколькими конструкторами. Аргументы метода конструктора и фабрики фактически необходимы по умолчанию, но с некоторыми специальными правилами в сценарии с одним конструктором, например, при многоэлементных точках введения (массивы, коллекции, ассоциативные массивы), разрешаются в пустые экземпляры, если нет подходящих бинов. Это позволяет использовать общий шаблон реализации, в котором все зависимости могут быть объявлены в уникальном многоаргументном конструкторе - например, объявлены как один публичный конструктор без аннотации @Autowired
.
Только один конструктор любого класса бина может объявить @Autowired
с атрибутом required
, заданным в true
, что указывает конструктору осуществлять автоматический поиск и связывание при использовании в качестве бина Spring. Как следствие, если атрибут required
оставить в значении по умолчанию true
, только один конструктор можно будет аннотировать с помощью @Autowired
. Если несколько конструкторов объявляют данную аннотацию, все они должны объявить required=false
, чтобы считаться компонентами-кандидатами на автоматическое обнаружение и связывание (аналогично autowire=constructor
в XML). Будет выбран конструктор с наибольшим количеством зависимостей, которые могут быть удовлетворены соответствующими бинами в контейнере Spring. Если ни один из компонентов-кандидатов не может быть удовлетворен, то будет использован первичный конструктор/конструктор по умолчанию (если он есть). Аналогично, если класс объявляет несколько конструкторов, но ни один из них не аннотирован @Autowired
, то будет использован первичный конструктор/конструктор по умолчанию (если он есть). Если в классе изначально объявлен только один конструктор, он всегда будет использован, даже если не аннотирован. Обратите внимание, что аннотированный конструктор не обязательно должен быть публичным.
Атрибут required
аннотации @Autowired
рекомендуется использовать вместо устаревшей аннотации @Required
для устанавливающих методов. Установка атрибута required
в false
означает, что свойство не требуется для целей автоматического обнаружения и связывания, и свойство будет проигнорировано, если оно не может быть автоматически обнаружено и связано. С другой стороны, атрибут @Required
является более строгим, поскольку принуждает устанавливать свойство любым способом, поддерживаемым контейнером, а если значение не определено, то возникает соответствующее исключение.
Как вариант, можно выразить необязательный характер конкретной зависимости с помощью java.util.Optional
в Java 8, как показано в следующем примере:
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(Optional<MovieFinder> movieFinder) {
...
}
}
Начиная со Spring Framework 5.0, вы также можете использовать аннотацию @Nullable
(любого типа в любом пакете, например, javax.annotation.Nullable
из JSR-305) или просто использовать встроенную в Kotlin поддержку null-безопасности::
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
...
}
}
class SimpleMovieLister {
@Autowired
var movieFinder: MovieFinder? = null
// ...
}
Вы также можете использовать @Autowired
для интерфейсов, которые являются известными разрешаемыми зависимостями: BeanFactory
, ApplicationContext
, Environment
, ResourceLoader
, ApplicationEventPublisher
и MessageSource
. Эти интерфейсы и их расширенные интерфейсы, такие как ConfigurableApplicationContext
или ResourcePatternResolver
, разрешаются автоматически, без необходимости специальной настройки. В следующем примере выполняется автоматический поиск и связывание объекта ApplicationContext
:
public class MovieRecommender {
@Autowired
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
class MovieRecommender {
@Autowired
lateinit var context: ApplicationContext
// ...
}
Аннотации @Autowired
, @Inject
, @Value
и @Resource
обрабатываются реализациями BeanPostProcessor
в Spring. Это означает, что невозможно применять эти аннотации внутри ваших собственных типов BeanPostProcessor
или BeanFactoryPostProcessor
(если таковые имеются). Эти типы должны быть "связаны" явным образом с помощью XML или метода @Bean
в Spring.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ