Что значит опциональный инжект в Spring?
Что проверяют
Знаете ли способы сказать контейнеру «этого бина может не быть», и различаете ли их по поведению на старте приложения. Заодно проверяют, не сидите ли вы до сих пор на инъекции в поля.
Как отвечать
Опциональный инжект это внедрение зависимости, отсутствие которой не должно ронять контекст. Обычный @Autowired требует ровно один подходящий бин, иначе при старте летит NoSuchBeanDefinitionException.
Варианты по возрастанию удобства:
@Autowired(required = false): бина нет, поле остаётсяnull;@Nullableна параметре конструктора или сеттера: то же самое, но читается лучше и дружит с конструкторной инъекцией;Optional<SomeService>как тип параметра: контейнер подставит пустойOptionalвместоnull;ObjectProvider<SomeService>: самый гибкий вариант, даётgetIfAvailable(),getIfUnique()и получение уже после старта, что помогает и с циклическими связями;- коллекция
List<Handler>: если реализаций нет, придёт пустой список, отдельного признака не нужно.
public class Report {
private final Optional<Exporter> exporter;
public Report(Optional<Exporter> exporter) {
this.exporter = exporter;
}
}Полезно назвать, когда это уместно: необязательная интеграция, компонент только для части профилей, подключаемый стартер. И когда неуместно: если без зависимости класс работать не может, честнее упасть на старте, чем ловить NullPointerException под нагрузкой.
Где спотыкаются
Вешают @Autowired(required = false) на поле с final. Так не работает: поле с final обязан заполнить конструктор, а инъекция в поле происходит уже после создания объекта.
Второе: сделали зависимость необязательной и не проверяют её перед вызовом. Опциональность переносит падение со старта в рантайм, и без проверки это ухудшение, а не выигрыш.
Третье: путают отсутствие бина с неоднозначностью. Если подходящих реализаций несколько, required = false не спасёт, нужен @Qualifier или @Primary.