我是春季启动应用程序,已经在一个自动配置类中创建了一个bean,它来自一个依赖的jar,比如bellow:
@Bean
@Order(100)
public StaticRouteLocator staticRouteLocator(AdminServerProperties admin) {
Collection<ZuulRoute> routes = Collections
.singleton(new ZuulRoute(admin.getContextPath() + "/api/turbine/stream/**",
properties.getUrl().toString()));
return new StaticRouteLocator(routes, server.getServletPrefix(), zuulProperties);
}
现在我想替换这个bean,但我仍然需要这个有不必要的Bean创建的jar。所以我在我的主要自动配置类中添加了另一个bean创建方法,如下所示:
@Bean(name="patchedStaticRouteLocator")
@Order(10)
@Primary
@ConditionalOnMissingBean
public StaticRouteLocator patchedStaticRouteLocator(AdminServerProperties admin) {
Collection<ZuulProperties.ZuulRoute> routes = Collections
.singleton(new ZuulProperties.ZuulRoute(admin.getContextPath(),
properties.getUrl().toString()));
return new StaticRouteLocator(routes, server.getServletPrefix(), zuulProperties);
}
但是这无法替换目标bean。错误消息清晰易懂:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.cloud.netflix.zuul.filters.RouteLocator] is defined: more than one 'primary' bean found among candidates: [routeLocator, patchedStaticRouteLocator, staticRouteLocator, compositeRouteLocator, applicationRouteLocator]
我的问题是什么是在春季靴子中更换这种现有豆子的正确方法?提前谢谢。
答案 0 :(得分:5)
这种情况下的问题是,您没有使用名称staticRouteLocator替换此bean。您正在创建另一个名为patchedStaticRouteLocator的bean。这一般不会成为问题,但似乎并不是你想要的。
引发NoUniqueBeanDefinitionException
是因为您还添加了@Primary
注释,现在至少有两个bean被标记为主要布线候选者。 Spring不知道它现在该做什么。
如果您真的想要覆盖第一个bean,请为其指定相同的名称。默认名称(如果没有明确指定其他名称)将是您在@Configuration
类中定义的方法的名称。在你的情况下,这将是patchedStaticRouteLocator。 (目前您还使用@Bean
注释name
属性再次定义了相同的名称,这是多余的,不需要。)
如果要使用name / alias staticRouteLocator替换bean,请为新bean指定相同的名称,因此请将其定义为:
@Bean(name="staticRouteLocator")
那应该覆盖第一个bean。
您可以使用以下支票计算您的咖啡豆:
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class BeanConfigTest {
@Autowired
private ApplicationContext applicationContext;
@Test
public void countBeanNames() {
final String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
assertThat(beanDefinitionNames.length, is(1));
}
}
只需将1替换为您期望的计数(之前和之后)。
答案 1 :(得分:1)
通过实施BeanPostProcessor
:
@Component
@Slf4j
public class StaticRouteLocatorPostBeanProcessor implements BeanPostProcessor {
@Autowired
private TurbineProperties properties;
@Autowired
private ServerProperties server;
@Autowired
private ZuulProperties zuulProperties;
@Autowired
private AdminServerProperties adminServerProperties;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (StaticRouteLocator.class.isAssignableFrom(bean.getClass())) {
Collection<ZuulProperties.ZuulRoute> routes = Collections
.singleton(new ZuulProperties.ZuulRoute(adminServerProperties.getContextPath(),
properties.getUrl().toString()));
log.info("Began to replace the StaticRouteLocator bean.");
return new StaticRouteLocator(routes, server.getServletPrefix(), zuulProperties);
}
return bean;
}
}