SpringBoot Basics Условное внедрение bean-компонентов Положение использования @Condition

Java задняя часть Spring контейнер

В предыдущих базовых сообщениях блога о bean-компонентах основное внимание уделялось определению и использованию bean-компонентов, но есть ли какие-либо сценарии, в которых определяемые мной bean-компоненты не загружаются или определенные мной bean-компоненты загружаются только при выполнении определенных предварительных условий? А как же Бин?

В этом сообщении в блоге в основном будут представлены условные аннотации при загрузке bean-компонентов.@ConditionalСвязанное использование

I. @Conditionalаннотация

Эта аннотация была введена в Spring4, и ее основная функция состоит в том, чтобы определить, выполняются ли условия, чтобы решить, следует ли инициализировать и регистрировать Bean-компонент в контейнере.

1. Определения

@ConditionalАннотация определяется следующим образом, которая в основном использует интерфейс Condition, чтобы определить, выполняются ли условия, чтобы решить, следует ли загружать Bean.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}

НижеCondtionМожно сказать, что определение интерфейса является самой базовой записью.Все остальные условные аннотации, в конечном счете, расширяются за счет реализации этого интерфейса.

@FunctionalInterface
public interface Condition {
    boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}

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

public interface ConditionContext {
    // 获取Bean定义
    BeanDefinitionRegistry getRegistry();

    // 获取Bean工程,因此就可以获取容器中的所有bean
    @Nullable
    ConfigurableListableBeanFactory getBeanFactory();

    // environment 持有所有的配置信息
    Environment getEnvironment();
    
    // 资源信息
    ResourceLoader getResourceLoader();

    // 类加载信息
    @Nullable
    ClassLoader getClassLoader();
}

2. Инструкция по применению

На небольшом примере кратко расскажите о том, как использовать Condition и@ConditionalАннотация для достижения условной загрузки bean-компонентов

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

public class RandDataComponent<T> {
    private Supplier<T> rand;

    public RandDataComponent(Supplier<T> rand) {
        this.rand = rand;
    }

    public T rand() {
        return rand.get();
    }
}

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

@Configuration
public class ConditionalAutoConfig {

    @Bean
    @Conditional(RandIntCondition.class)
    public RandDataComponent<Integer> randIntComponent() {
        return new RandDataComponent<>(() -> {
            Random random = new Random();
            return random.nextInt(1024);
        });
    }

    @Bean
    @Conditional(RandBooleanCondition.class)
    public RandDataComponent<Boolean> randBooleanComponent() {
        return new RandDataComponent<>(() -> {
            Random random = new Random();
            return random.nextBoolean();
        });
    }
}

Вышеупомянутая конфигурация, независимо от@ConditionalСодержание аннотации, просто посмотрите на определения двух bean-компонентов, один из которых определяет генерацию случайных чисел int, другой определяет генерацию случайных логических значений;

Но в нашей системе нам нужен только генератор случайных данных, выбираем по конфигурацииconditional.rand.typeЗначение, чтобы выбрать, какое из них использовать, конфигурация выглядит следующим образом

# int 表示选择随机产生int数据; 非int 表示随机产生boolean数据
conditional.rand.type=int

Далее мы должны посмотреть, как добавляется это условие, то есть указанный выше класс конфигурацииConditionalAutoConfigВ содержании двух аннотаций реализованы оба классаConditionинтерфейс, как показано ниже

public class RandBooleanCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String type = conditionContext.getEnvironment().getProperty("conditional.rand.type");
        return "boolean".equalsIgnoreCase(type);
    }
}

public class RandIntCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String type = conditionContext.getEnvironment().getProperty("conditional.rand.type");
        return "int".equalsIgnoreCase(type);
    }
}

Вышеупомянутая реализация также относительно понятна, получите значение конфигурации, затем оцените и верните true/fase; если возвращается true, это означает, что условие выполнено, тогда бин может быть загружен; в противном случае бин не будет создан

3. Тестирование и проверка

Для приведенной выше конфигурации и реализации напишите тестовый класс следующим образом.

@RestController
@RequestMapping(path = "/conditional")
public class ConditionalRest {

    @Autowired
    private RandDataComponent randDataComponent;

    @GetMapping(path = "/show")
    public String show() {
        String type = environment.getProperty("conditional.rand.type");
        return randDataComponent.rand() + " >>> " + type;
    }
}

Когда значением файла конфигурации является int, каждый доступ должен возвращать положительное целое число, как показано на следующем рисунке.

int随机生成

После изменения настроенного значения на логическое значение снова проверьте, как показано ниже.

boolean随机生成

II. ПРОДОЛЖЕНИЕ И РЕЗЮМЕ

Вышеприведенный тест демонстрирует случай выбора bean-компонента для внедрения через файл конфигурации.Если bean-компонент загружается посредством автоматического сканирования, можно ли его напрямую добавить в класс bean-компонента, чтобы решить, загружать его или нет?

1. Автоматически сканировать условную загрузку bean-компонентов

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

@Component
@Conditional(ScanDemoCondition.class)
public class ScanDemoBean {

    @Value("${conditional.demo.load}")
    private boolean load;

    public boolean getLoad() {
        return load;
    }
}

Соответствующие условия оценки следующие, когда файл конфигурацииconditional.demo.loadПри значении true эта конфигурация будет загружена, в противном случае она не будет создана.

public class ScanDemoCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return "true".equalsIgnoreCase(conditionContext.getEnvironment().getProperty("conditional.demo.load"));
    }
}

Тестовый класс аналогичен предыдущему, небольшое внимание — изменение необходимых условий при автоматическом внедрении, чтобы избежать ошибки, когда бин не существует.

@Autowired(required = false)
private ScanDemoBean scanDemoBean;

@GetMapping(path = "/scan")
public String showDemo() {
    String type = environment.getProperty("conditional.demo.load");
    if (scanDemoBean == null) {
        return "not exists! >>>" + type;
    } else {
        return "load : " + scanDemoBean.getLoad() + " >>>" + type;
    }
}

Если установлено значение true, bean-компонент должен существовать, следуйте приведенной выше логике else.

自动扫描条件准确

Когда конфигурация ложна, bean-компонент не будет загружен, и будет выполняться логика if.

自动扫描添加不符

2. Резюме

пройти через@ConditionalАннотации подходятConditionИнтерфейс для принятия решения о создании и регистрации bean-компонента в контейнере Spring, чтобы обеспечить выборочную загрузку bean-компонентов.

А. Преимущества

Какова цель этого?

  • Как выбрать, когда есть несколько бинов с одинаковым именем
  • Решите случай, когда некоторые bean-компоненты создаются с другими зависимостями.

б. Дополнительные примечания

Вышеупомянутое может управлять созданием bean-компонентов, но через описанный выше процесс вы обнаружите, что он немного громоздкий.Есть ли способ упростить описанный выше процесс?

Просто используйте одну аннотацию, не реализуйте интерфейс Condtion самостоятельно, среда Spring предоставляет ряд связанных аннотаций, как показано в следующей таблице.

аннотация иллюстрировать
@ConditionalOnSingleCandidate Возвращает true, когда существует bean-компонент данного типа и существует заданный тип, указанный как Primary
@ConditionalOnMissingBean Возвращает true, если заданный тип, имя класса, аннотация, псевдоним не существует в beanFactory Связь между каждым типом или
@ConditionalOnBean В отличие от вышесказанного, требуется, чтобы bean-компонент существовал
@ConditionalOnMissingClass Возвращает true, если заданное имя класса не существует в пути к классам, и отношение между каждым типом равно и
@ConditionalOnClass В отличие от вышесказанного, требуется, чтобы класс существовал
@ConditionalOnCloudPlatform Верните True, когда настроенную CloudPlatform активируется
@ConditionalOnExpression выражение spel выполняется как истинное
@ConditionalOnJava Содержит ли номер версии Java во время выполнения заданный номер версии. Если он содержит, верните совпадение, в противном случае верните несоответствие
@ConditionalOnProperty Требовать, чтобы свойства конфигурации соответствовали критериям
@ConditionalOnJndi Местоположение должно существовать для данного jndi. В противном случае совпадение не возвращается.
@ConditionalOnNotWebApplication Когда веб-среда не существует
@ConditionalOnWebApplication Когда существует веб-среда
@ConditionalOnResource Ресурсы, необходимые для развития, существуют

III. Другое

0. Актуально

А. Больше сообщений в блоге

Основы

Заявление

б. Исходный проект

1. Серый блог

  • One Grey BlogПерсональный блогblog.hhui.top
  • Серый блог - специальный весенний блогspring.hhui.top

Серый личный блог, записывающий все посты блога по учебе и работе, приглашаю всех в гости

2. Заявление

Это не так хорошо, как письмо. Вышеупомянутое содержание чисто из семьи. Из-за ограниченных личных способностей неизбежно будут упущения и ошибки. Если вы обнаружите ошибки или у вас есть лучшие предложения, вы можете критиковать и поправьте их.

3. Сканируйте внимание

серый блог

QrCode