Подключение теста в Spring Boot 2.1 без включения переопределения bean-компонентов

У меня есть код с именованными бобами

@Bean
@Named("heimdall-uri-supplier")
public URISupplier heimdallEndpointSupplier(CredentialsClientConfig config, EnvInfo envInfo) {
    ....
}

@Named("vault-uri-supplier")
@Bean
public URISupplier vaultURISupplier(EnvInfo envInfo, CredentialsClientConfig config) {
   ....
}

Они явно названы, потому что я хочу, чтобы конкретные реализации внедрялись в разные классы-потребители. Эти классы также используют @Named.

В тестах до Spring Boot 2.1

@Bean
@Primary
@Named("heimdall-uri-supplier")
public URISupplier heimdallEndpointSupplier(CredentialsClientConfig config, EnvInfo envInfo) {
    return mock of some sort
}

@Named("vault-uri-supplier")
@Bean
@Primary
public URISupplier vaultURISupplier(EnvInfo envInfo, CredentialsClientConfig config) {
   return mock of some sort
}

отлично поработал.

Теперь, конечно, Spring Boot 2.1 отключает переопределение. Я знаю, что могу включить его снова, но теоретически я бы предпочел не делать этого.

Но мой "нормальный" обходной путь (do @Bean (name = "testFoo") здесь не сработает, потому что инжектор @Named в потребляющих классах теперь выйдет из строя.

Есть какие-нибудь решения?

Чтобы было ясно: если бы я не использовал Named, у меня не было бы этой проблемы. Я использую Named, потому что создаю два bean-компонента одного типа, но хочу, чтобы они вводились в разные потребляющие bean-компоненты. По-настоящему УЖАСНЫЙ обходной путь - это ввести Set, а затем взять «правильный», но это хакерский хакерский хакерский прием.

Mike Bell 04.01.2019 21:27
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
4
1
241
1

Ответы 1

Мне это удалось, но это было довольно болезненно. Пришлось использовать BeanDefinitionRegistryPostProcessor. Настроить GenericBeanDefinition уродливо, как грех. Здесь было не так уж и плохо, потому что моки не являются аргументами. Если вам нужно основывать их на введенных или заданных аргументах конструктора, это действительно становится довольно сложным.

/**
 * This class basically removes the existing bean definition and substitutes in the mocks.
 * Normally we don't need this - we just change the bean name. However because the
 * classes use an @Named qualifier, more heroic efforts are needed
 */
public static class OverridePostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry) throws BeansException {
        if (registry.isBeanNameInUse("vault-uri-supplier")) {
            registry.removeBeanDefinition("vault-uri-supplier");
        }
        // Note: These are a bear to work with, but in theory you can build
        // them from scratch based on injected beans etc. Fortunately these
        // two examples just needed a no-args supplier
        GenericBeanDefinition g = new GenericBeanDefinition();
        g.setBeanClass(URISupplier.class);
        g.setInstanceSupplier(this::vaultURISupplier);
        registry.registerBeanDefinition("vault-uri-supplier", g);
        if (registry.isBeanNameInUse("taskRequestValidator")) {
            registry.removeBeanDefinition("taskRequestValidator");
        }
        g = new GenericBeanDefinition();
        g.setBeanClass(TaskRequestValidator.class);
        g.setInstanceSupplier(this::taskRequestValidator);
        registry.registerBeanDefinition("taskRequestValidator", g);


    }

    URISupplier vaultURISupplier() {
        return new com.opentable.credentials.client.internal.TestVaultConfiguration.MockSupplier();
    }
    TaskRequestValidator taskRequestValidator() {
        return (getTokenRequest, servicePolicy) -> ValidationResult.OK;
    }

    @Override
    public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {
        /* No op */
    }
}
jira.spring.io/browse/SPR-17519 было бы лучшим решением IMO.
Mike Bell 05.01.2019 20:19

Другие вопросы по теме