2017-01-17 36 views
1

我春天啓動應用程序,目前已經是一個bean創建一個自動configuraton類從一個依賴的jar像波紋管:如何在彈簧引導應用程序中替換現有的bean?

@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,但我仍然需要這個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] 

我的問題什麼是正確的方式來取代這種現有的bean在春季啓動?提前致謝。

回答

2

這種情況下的問題是,您沒有用名稱staticRouteLocator替換此bean。您正在創建名爲patchedStaticRouteLocator的另一個bean。這通常不會成爲問題,但看起來不是你想要的。

NoUniqueBeanDefinitionException是因爲您還添加了@Primary註釋而現在至少有兩個bean被標記爲主要接線候選。春天不知道現在該做什麼。

如果您確實想覆蓋第一個bean,請爲其指定相同的名稱。默認名稱(如果沒有明確指定其他名稱)將是您在@Configuration類中定義的方法的名稱。在你的情況下,這將patchedStaticRouteLocator。如果要更換名稱/別名staticRouteLocator豆,給你的新豆一樣的(目前也再次與@Bean註解定義同名name財產,這是一種多餘的,沒有必要的。)

名字,所以將它定義成:

@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次。

+0

感謝它清理我的一些混亂的,雖然如預期這個解決方案沒有工作上面的指示。不過,我通過實現一個BeanPostProcessor組件來完成它。 – leo

+0

不客氣。不過很高興你找到了一個可行的解決方案 –

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; 
    } 
} 
相關問題