@Conditional бин и необязательная зависимость @Autowired(required=false)

В общем случае рекомендуется внедрять зависимости через конструктор. Но необязательные зависимости рекомендуется внедрять через сеттер.

В этой статье пойдет речь о @Conditional бин.

@Conditional бин

Допустим, в проекте есть необязательный бин, который создается (либо нет) в зависимости от условия: окружения, версии jre, свойства в application.properties.

Например, логгер в production-среде может быть один, а в develepment-среде — другой. Но мы сделаем еще проще — создадим бин Logger, который либо создается, либо нет в зависимости от настройки в application.properties:

logger=true

Для этого аннотируем бин Logger с помощью @ConditionalOnExpression:

@Component
@ConditionalOnExpression("${logger:true}")
public class Logger {
    public void log(String message){
        System.out.println("log");
    }
}

Вариантов поставить условия очень много, мы рассматриваем  только @ConditionalOnExpression (внутри задается SPEL-выражение), но тут подошел бы и @ConditionalOnProperty:

Подсказки

Итак, выше с помощью аннотации:

@ConditionalOnExpression("${logger:true}")

мы задали, что бин Logger создается только в том случае, если свойство logger=true. Иначе он не создается.

Нежелательно внедрять бин Logger в другой бин AnimalRepository через конструктор AnimalRepository. Потому что внедрение через конструктор подразумевает, что все внедряемые бины уже созданы к моменту вызова конструктора. То есть сначала Logger, потом AnimalRepository. В случае же logger=false бин Logger отсутствует.

Поэтому необязательный бин внедрим через сеттер.

@Autowired(required=false) и внедрение через сеттер

То, что зависимость не обязательная, указывается с помощью аннотации:

@Autowired(required=false)

Итак, класс AnimalRepository с необязательной зависимостью выглядит так:

@Repository
public class AnimalRepository {

    private Logger logger;

    @Autowired(required = false)
    public void setLogger(Logger logger) {
        this.logger = logger;
    }

    public void save() {
        if (logger != null)
            logger.log("logged");
        System.out.println("save method");
    }
}

AnimalRepository создается вне зависимости от настройки logger.

А с необязательной зависимостью обходятся так, как показано выше — проверяют ее на null. (Хотя есть еще вариант просто присвоить некий логгер по умолчанию, но опустим этот вариант).

Проверка

Можно написать тест и убедиться, что контекст успешно создается при любом значении свойства logger. А логирование происходит только при logger=true.

@SpringBootTest
class MainTests {
    @Autowired
    private AnimalRepository animalRepository;

    @Test
    void whenLogger_thenLog() {
        animalRepository.save();
    }

}

Код примера доступен на GitHub.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *