我有使用命名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会禁用覆盖。我知道我可以重新启用它,但是从理论上讲我不愿意这样做。
但是我的“常规”解决方法(做@Bean(name =“ testFoo”)在这里不起作用,因为使用类中的@Named注入器现在将失败。
有什么解决办法吗?
答案 0 :(得分:0)
我设法做到了,但这确实很痛苦。我必须使用BeanDefinitionRegistryPostProcessor
。设置GenericBeanDefinition
很丑陋。在这里还不错,因为模拟是无参数的。如果必须将它们基于注入或设置构造函数args,则确实会涉及到很多事情。
/**
* 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 */
}
}