首页 文章

如何在spring boot应用程序中替换现有的bean?

提问于
浏览
2

我是 Spring 季启动应用程序,已经在一个自动配置类中创建了一个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]

我的问题是什么是在 Spring 季靴子中更换这种现有 beans 子的正确方法?提前致谢 .

2 回答

  • 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;
      }
    }
    
  • 4

    在这种情况下的问题是,您没有使用名称staticRouteLocator替换此bean . 您正在创建名为patchedStaticRouteLocator的另一个bean . 这一般不会成为问题,但似乎不是你想要的 .

    引发了 NoUniqueBeanDefinitionException ,因为您还添加了 @Primary 注释,现在至少有两个bean被标记为主要布线候选者 . Spring 天不知道它现在该做什么 .

    如果您真的想要覆盖第一个bean,请为其指定相同的名称 . 默认名称(如果没有明确指定其他名称)将是您在 @Configuration 类中定义的方法的名称 . 在你的情况下,这将是patchedStaticRouteLocator . (目前您还使用 @Bean annotations name 属性再次定义相同的名称,这是多余的,不需要 . )

    如果要使用name / alias staticRouteLocator替换bean,请为新bean指定相同的名称,因此请将其定义为:

    @Bean(name="staticRouteLocator")

    这应该覆盖第一个bean .

    您可以使用以下支票计算您的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替换为您期望的计数(之前和之后) .

相关问题