diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonApplicationContextInitializer.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonApplicationContextInitializer.java new file mode 100644 index 00000000..ce8782b9 --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonApplicationContextInitializer.java @@ -0,0 +1,38 @@ +package org.springframework.cloud.netflix.ribbon; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; + +import java.util.List; + +/** + * Responsible for eagerly creating the child application context holding the Ribbon + * related configuration + * + * @author Biju Kunjummen + */ +public class RibbonApplicationContextInitializer + implements ApplicationListener { + + private final SpringClientFactory springClientFactory; + private final List serviceIds; + + public RibbonApplicationContextInitializer(SpringClientFactory springClientFactory, + List serviceIds) { + this.springClientFactory = springClientFactory; + this.serviceIds = serviceIds; + } + + private void initialize() { + if (serviceIds != null) { + for (String serviceId : serviceIds) { + this.springClientFactory.getContext(serviceId); + } + } + } + +// @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + initialize(); + } +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/SpringClientFactory.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/SpringClientFactory.java index 7dbccf5d..f3ebd424 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/SpringClientFactory.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/SpringClientFactory.java @@ -80,28 +80,29 @@ public class SpringClientFactory extends NamedContextFactory C instantiateWithConfig(AnnotationConfigApplicationContext context, - Class clazz, IClientConfig config) { + Class clazz, IClientConfig config) { C result = null; - + try { Constructor constructor = clazz.getConstructor(IClientConfig.class); result = constructor.newInstance(config); - } catch (Throwable e) { + } + catch (Throwable e) { // Ignored } - + if (result == null) { result = BeanUtils.instantiate(clazz); - + if (result instanceof IClientConfigAware) { ((IClientConfigAware) result).initWithNiwsConfig(config); } - + if (context != null) { context.getAutowireCapableBeanFactory().autowireBean(result); } } - + return result; } @@ -115,5 +116,8 @@ public class SpringClientFactory extends NamedContextFactory getServiceIdsFromZuulProps(ZuulProperties zuulProperties) { + Map zuulRoutes = zuulProperties.getRoutes(); + Collection registeredRoutes = zuulRoutes.values(); + List serviceIds = new ArrayList<>(); + if (registeredRoutes != null) { + for (ZuulProperties.ZuulRoute route: registeredRoutes) { + String serviceId = route.getServiceId(); + if (serviceId != null) { + serviceIds.add(serviceId); + } + } + } + return serviceIds; + } +} diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonApplicationContextInitializerTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonApplicationContextInitializerTests.java new file mode 100644 index 00000000..9b34ad60 --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonApplicationContextInitializerTests.java @@ -0,0 +1,80 @@ +package org.springframework.cloud.netflix.ribbon; + +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.cloud.netflix.archaius.ArchaiusAutoConfiguration; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.util.EnvironmentTestUtils.addEnvironment; + +/** + * @author Biju Kunjummen + */ + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {RibbonAutoConfiguration.class, + ArchaiusAutoConfiguration.class, RibbonApplicationContextInitializerTests.RibbonInitializerConfig.class}) +@DirtiesContext +public class RibbonApplicationContextInitializerTests { + + @Autowired + private SpringClientFactory springClientFactory; + + @Test + public void testContextShouldInitalizeChildContexts() { + + // Context should have been initialized and an instance of Foo created + assertThat(Foo.getInstanceCount()).isEqualTo(1); + ApplicationContext ctx = springClientFactory.getContext("testspec"); + + assertThat(Foo.getInstanceCount()).isEqualTo(1); + Foo foo = ctx.getBean("foo", Foo.class); + assertThat(foo).isNotNull(); + } + + @Configuration + static class FooConfig { + + @Bean + public Foo foo() { + return new Foo(); + } + + } + + @Configuration + @RibbonClient(name="testspec", configuration = FooConfig.class) + static class RibbonInitializerConfig { + + @Bean + public RibbonApplicationContextInitializer ribbonApplicationContextInitializer( + SpringClientFactory springClientFactory) { + return new RibbonApplicationContextInitializer(springClientFactory, + Arrays.asList("testspec")); + } + + } + + static class Foo { + private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger(); + + public Foo() { + INSTANCE_COUNT.incrementAndGet(); + } + + public static int getInstanceCount() { + return INSTANCE_COUNT.get(); + } + } +} diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/apache/HttpClientRibbonCommandIntegrationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/apache/HttpClientRibbonCommandIntegrationTests.java index 6f420150..14f07e2b 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/apache/HttpClientRibbonCommandIntegrationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/apache/HttpClientRibbonCommandIntegrationTests.java @@ -79,7 +79,7 @@ import com.netflix.loadbalancer.ServerList; "zuul.routes.other: /test/**=http://localhost:7777/local", "zuul.routes.another: /another/twolevel/**", "zuul.routes.simple: /simple/**", "zuul.routes.singleton: /singleton/**", - "zuul.routes.singleton.sensitiveHeaders: " }) + "zuul.routes.singleton.sensitiveHeaders: ","zuul.context.startup.enabled: true" }) @DirtiesContext public class HttpClientRibbonCommandIntegrationTests extends ZuulProxyTestBase {