Spring IoC контейнер: конфигурация на основе аннотаций, использование @Autowired

Вы можете применить аннотацию @Autowired к конструкторам, как показано в следующем примере:

Java

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

Kotlin

class MovieRecommender @Autowired constructor(
    private val customerPreferenceDao: CustomerPreferenceDao)

Начиная с Spring Framework 4.3, аннотация @Autowired для такого конструктора больше не требуется, если целевой бин для начала определяет только один конструктор. Однако, если доступно несколько конструкторов и нет основного/стандартного конструктора, по крайней мере один из конструкторов должен быть аннотирован @Autowired, чтобы указать контейнеру, какой из них использовать.

Вы также можете применить аннотацию @Autowired к традиционным методам установки, как показано в следующем примере:

Java

public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

    // ...
}

Kotlin

class SimpleMovieLister {

    @Autowired
    lateinit var movieFinder: MovieFinder

    // ...

}

Вы также можете применить аннотацию к методам с произвольными именами и несколькими аргументами, как показано в следующем примере:

Java

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

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

    // ...
}

Kotlin

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 к полям и даже смешивать их с конструкторами, как показано в следующем примере:

Java

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    private MovieCatalog movieCatalog;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

Kotlin

class MovieRecommender @Autowired constructor(
    private val customerPreferenceDao: CustomerPreferenceDao) {

    @Autowired
    private lateinit var movieCatalog: MovieCatalog

    // ...
}

Убедитесь, что ваши целевые компоненты (например, MovieCatalog или CustomerPreferenceDao) последовательно объявляются в соответствии с типом, который вы используете для точек внедрения, помеченных @Autowired. В противном случае внедрение может завершиться неудачей из-за ошибки "no type match found" ("не найдено совпадение типов") во время выполнения.

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

Вы также можете указать Spring предоставить все компоненты определенного типа из ApplicationContext, добавив аннотацию @Autowired в поле или метод, который ожидает массив этого типа, как показано в следующем примере:

Java

public class MovieRecommender {

    @Autowired
    private MovieCatalog[] movieCatalogs;

    // ...
}

Kotlin

class MovieRecommender {

    @Autowired
    private lateinit var movieCatalogs: Array<MovieCatalog>

    // ...
}

То же самое относится к типизированным коллекциям, как показано в следующем примере:

Java

public class MovieRecommender {

    private Set<MovieCatalog> movieCatalogs;

    @Autowired
    public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
        this.movieCatalogs = movieCatalogs;
    }

    // ...
}

Kotlin

class MovieRecommender {

    @Autowired
    lateinit var movieCatalogs: Set<MovieCatalog>

    // ...
}

Ваши целевые bean-компоненты могут реализовать интерфейс org.springframework.core.Ordered или использовать аннотацию @Order или стандартную @Priority, если вы хотите, чтобы элементы в массиве или списке сортировались в определенном порядке. В противном случае их порядок следует порядку регистрации соответствующих определений целевого компонента в контейнере.

Вы можете объявить аннотацию @Order на уровне целевого класса и в методах @Bean, потенциально для отдельных определений бинов (в случае нескольких определений, использующих один и тот же класс бинов). Значения @Order могут влиять на приоритеты в точках внедрения, но имейте в виду, что они не влияют на порядок запуска синглтона, что является ортогональной проблемой, определяемой отношениями зависимостей и объявлениями @DependsOn.

Обратите внимание, что стандартная аннотация javax.annotation.Priority недоступна на уровне @Bean, поскольку она не может быть объявлена ​​в методах. Ее семантика может быть смоделирована с помощью значений @Order в сочетании с @Primary для одного компонента для каждого типа.

Даже типизированные экземпляры Map могут быть подключены автоматически, если ожидаемый тип ключа - String. Значения карты содержат все bean-компоненты ожидаемого типа, а ключи содержат соответствующие имена bean-компонентов, как показано в следующем примере:

Java

public class MovieRecommender {

    private Map<String, MovieCatalog> movieCatalogs;

    @Autowired
    public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
        this.movieCatalogs = movieCatalogs;
    }

    // ...
}

Kotlin

class MovieRecommender {

    @Autowired
    lateinit var movieCatalogs: Map<String, MovieCatalog>

    // ...
}

По умолчанию автоматическое подключение завершается ошибкой, когда для данной точки внедрения отсутствуют подходящие подходящие компоненты. В случае объявленного массива, коллекции или карты ожидается, по крайней мере, один соответствующий элемент.

Поведение по умолчанию состоит в том, чтобы рассматривать аннотированные методы и поля как указывающие на необходимые зависимости. Вы можете изменить это поведение, как показано в следующем примере, позволяя платформе пропускать недопустимую точку внедрения, помечая ее как необязательную (т. е. устанавливая обязательный атрибут в @Autowired равным false):

Java

public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

    // ...
}

Kotlin

class SimpleMovieLister {

    @Autowired(required = false)
    var movieFinder: MovieFinder? = null

    // ...
}

Необязательный метод вообще не будет вызываться, если его зависимость (или одна из его зависимостей в случае нескольких аргументов) недоступна. В таких случаях необязательное поле не заполняется вообще, а его значение по умолчанию остается на месте.

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

Только один конструктор из любого заданного класса bean-компонента может объявить @Autowired с обязательным атрибутом, установленным в true, что указывает на конструктор для автоматической передачи при использовании в качестве Spring-компонента. Как следствие, если для обязательного атрибута оставлено значение по умолчанию true, только один конструктор может быть аннотирован @Autowired. Если несколько конструкторов объявляют аннотацию, все они должны будут объявить required=false, чтобы их можно было рассматривать в качестве кандидатов на автопривязку (аналог autowire=constructor в XML). Будет выбран конструктор с наибольшим количеством зависимостей, который может быть удовлетворен путем сопоставления bean-компонентов в контейнере Spring. Если ни один из кандидатов не может быть удовлетворен, то будет использоваться основной/заданный по умолчанию конструктор (если имеется). Точно так же, если класс объявляет несколько конструкторов, но ни один из них не аннотирован @Autowired, то будет использоваться основной/заданный по умолчанию конструктор (если имеется). Если класс для начала объявляет только один конструктор, он всегда будет использоваться, даже если он не аннотирован. Обратите внимание, что аннотированный конструктор не должен быть публичным.

Обязательный атрибут @Autowired рекомендуется использовать вместо устаревшей аннотации @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:

Java

public class SimpleMovieLister {

    @Autowired
    public void setMovieFinder(@Nullable MovieFinder movieFinder) {
        ...
    }
}

Kotlin

class SimpleMovieLister {

    @Autowired
    var movieFinder: MovieFinder? = null

    // ...
}

Вы также можете использовать @Autowired для интерфейсов, которые являются хорошо известными разрешаемыми зависимостями: BeanFactory, ApplicationContext, Environment, ResourceLoader, ApplicationEventPublisher и MessageSource. Эти интерфейсы и их расширенные интерфейсы, такие как ConfigurableApplicationContext или ResourcePatternResolver, автоматически разрешаются без специальной настройки. Следующий пример автоматически связывает объект ApplicationContext:

Java

public class MovieRecommender {

    @Autowired
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...
}

Kotlin

class MovieRecommender {

    @Autowired
    lateinit var context: ApplicationContext

    // ...
}

Аннотации @Autowired, @Inject, @Value и @Resource обрабатываются реализациями Spring BeanPostProcessor. Это означает, что вы не можете применять эти аннотации в ваших собственных типах BeanPostProcessor или BeanFactoryPostProcessor (если есть). Эти типы должны быть явно подключены с использованием XML или метода Spring @Bean.


Читайте также:


Комментарии

Популярные сообщения из этого блога

Методы класса Object в Java

Как получить текущий timestamp в Java

Основные опции JVM для повышения производительности и отладки