diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java index 4c455873..df3d8ad8 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java @@ -23,7 +23,7 @@ import com.netflix.client.IClient; */ @Configuration @ConditionalOnClass(IClient.class) -@EnableRibbonClient +@RibbonClients @AutoConfigureAfter(EurekaClientAutoConfiguration.class) public class RibbonAutoConfiguration { diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClient.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClient.java index a62a7c28..1b11d7c8 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClient.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClient.java @@ -21,10 +21,15 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + /** * @author Dave Syer * */ +@Configuration +@Import(RibbonClientConfigurationRegistrar.class) @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClientConfigurationRegistrar.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClientConfigurationRegistrar.java index 14c7846c..09aa7641 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClientConfigurationRegistrar.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClientConfigurationRegistrar.java @@ -33,18 +33,30 @@ public class RibbonClientConfigurationRegistrar implements ImportBeanDefinitionR public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { Map attrs = metadata.getAnnotationAttributes( - EnableRibbonClient.class.getName(), true); - if (attrs.containsKey("value")) { + RibbonClients.class.getName(), true); + if (attrs != null && attrs.containsKey("value")) { AnnotationAttributes[] clients = (AnnotationAttributes[]) attrs.get("value"); - for (AnnotationAttributes attr : clients) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder - .genericBeanDefinition(RibbonClientSpecification.class); - builder.addConstructorArgValue(attr.get("name")); - builder.addConstructorArgValue(attr.get("configuration")); - registry.registerBeanDefinition(attr.get("name") - + "RibbonClientSpecification", builder.getBeanDefinition()); + for (AnnotationAttributes client : clients) { + registerClientConfiguration(registry, client.get("name"), + client.get("configuration")); } } + Map client = metadata.getAnnotationAttributes( + RibbonClient.class.getName(), true); + if (client != null && client.containsKey("name")) { + registerClientConfiguration(registry, client.get("name"), + client.get("configuration")); + } + } + + private void registerClientConfiguration(BeanDefinitionRegistry registry, + Object name, Object configuration) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder + .genericBeanDefinition(RibbonClientSpecification.class); + builder.addConstructorArgValue(name); + builder.addConstructorArgValue(configuration); + registry.registerBeanDefinition(name + "RibbonClientSpecification", + builder.getBeanDefinition()); } } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/EnableRibbonClient.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClients.java similarity index 86% rename from spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/EnableRibbonClient.java rename to spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClients.java index 0f75728e..5a170a74 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/EnableRibbonClient.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClients.java @@ -25,6 +25,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** + * Convenience annotation that allows user to combine multiple @RibbonClient + * annotations on a single class (including in Java 7). + * * @author Dave Syer * */ @@ -33,8 +36,8 @@ import org.springframework.context.annotation.Import; @Target({ ElementType.TYPE }) @Documented @Import(RibbonClientConfigurationRegistrar.class) -public @interface EnableRibbonClient { - +public @interface RibbonClients { + RibbonClient[] value() default {}; } diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/RibbonClientPreprocessorIntegrationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/RibbonClientPreprocessorIntegrationTests.java new file mode 100644 index 00000000..7bf6aed6 --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/RibbonClientPreprocessorIntegrationTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.netflix.ribbon.eureka; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration; +import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; +import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; +import org.springframework.cloud.netflix.ribbon.RibbonClient; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.cloud.netflix.ribbon.eureka.RibbonClientPreprocessorIntegrationTests.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.netflix.loadbalancer.Server; +import com.netflix.loadbalancer.ZoneAvoidanceRule; +import com.netflix.loadbalancer.ZoneAwareLoadBalancer; + +/** + * @author Dave Syer + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = TestConfiguration.class) +@DirtiesContext +public class RibbonClientPreprocessorIntegrationTests { + + @Autowired + private SpringClientFactory factory; + + @Test + public void serverListIsWrapped() throws Exception { + @SuppressWarnings("unchecked") + ZoneAwareLoadBalancer loadBalancer = (ZoneAwareLoadBalancer) factory + .getLoadBalancer("foo"); + DomainExtractingServerList.class.cast(loadBalancer.getServerListImpl()); + } + + @Test + public void ruleDefaultsToZoneAvoidance() throws Exception { + @SuppressWarnings("unchecked") + ZoneAwareLoadBalancer loadBalancer = (ZoneAwareLoadBalancer) factory + .getLoadBalancer("foo"); + ZoneAvoidanceRule.class.cast(loadBalancer.getRule()); + } + + @Test + public void serverListFilterOverride() throws Exception { + @SuppressWarnings("unchecked") + ZoneAwareLoadBalancer loadBalancer = (ZoneAwareLoadBalancer) factory + .getLoadBalancer("foo"); + assertEquals("myTestZone", + ZonePreferenceServerListFilter.class.cast(loadBalancer.getFilter()) + .getZone()); + } + + @Configuration + @RibbonClient(name = "foo", configuration = FooConfiguration.class) + @Import({ PropertyPlaceholderAutoConfiguration.class, + ArchaiusAutoConfiguration.class, EurekaClientAutoConfiguration.class, + RibbonAutoConfiguration.class, RibbonEurekaAutoConfiguration.class }) + protected static class TestConfiguration { + } + + @Configuration + protected static class FooConfiguration { + @Bean + public ZonePreferenceServerListFilter serverListFilter() { + ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter(); + filter.setZone("myTestZone"); + return filter; + } + } + +} diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientPreprocessorIntegrationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/RibbonClientsPreprocessorIntegrationTests.java similarity index 90% rename from spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientPreprocessorIntegrationTests.java rename to spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/RibbonClientsPreprocessorIntegrationTests.java index af146017..fc9cb671 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientPreprocessorIntegrationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/RibbonClientsPreprocessorIntegrationTests.java @@ -24,11 +24,11 @@ import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfigurati import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration; import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; -import org.springframework.cloud.netflix.ribbon.EnableRibbonClient; +import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.netflix.ribbon.SpringClientFactory; -import org.springframework.cloud.netflix.ribbon.eureka.EurekaRibbonClientPreprocessorIntegrationTests.TestConfiguration; +import org.springframework.cloud.netflix.ribbon.eureka.RibbonClientsPreprocessorIntegrationTests.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -46,7 +46,7 @@ import com.netflix.loadbalancer.ZoneAwareLoadBalancer; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = TestConfiguration.class) @DirtiesContext -public class EurekaRibbonClientPreprocessorIntegrationTests { +public class RibbonClientsPreprocessorIntegrationTests { @Autowired private SpringClientFactory factory; @@ -77,7 +77,7 @@ public class EurekaRibbonClientPreprocessorIntegrationTests { } @Configuration - @EnableRibbonClient(@RibbonClient(name = "foo", configuration = FooConfiguration.class)) + @RibbonClients(@RibbonClient(name = "foo", configuration = FooConfiguration.class)) @Import({ PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class, EurekaClientAutoConfiguration.class, RibbonAutoConfiguration.class, RibbonEurekaAutoConfiguration.class })