diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClientConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClientConfiguration.java index bedd87fb9..d5292dfa4 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClientConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonClientConfiguration.java @@ -19,17 +19,13 @@ package org.springframework.cloud.netflix.ribbon; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList; -import org.springframework.cloud.netflix.ribbon.eureka.ZonePreferenceServerListFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.netflix.client.config.DefaultClientConfigImpl; import com.netflix.client.config.IClientConfig; -import com.netflix.loadbalancer.DynamicServerListLoadBalancer; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; -import com.netflix.loadbalancer.ServerList; import com.netflix.loadbalancer.ServerListFilter; import com.netflix.loadbalancer.ZoneAwareLoadBalancer; import com.netflix.niws.client.http.RestClient; @@ -46,9 +42,6 @@ public class RibbonClientConfiguration { @Value("${ribbon.client.name}") private String name = "client"; - @Value("${ribbon.eureka.approximateZoneFromHostname:false}") - private boolean approximateZoneFromHostname = false; - // TODO: maybe re-instate autowired load balancers: identified by name they could be // associated with ribbon clients @@ -75,7 +68,6 @@ public class RibbonClientConfiguration { public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerListFilter filter) { ZoneAwareLoadBalancer balancer = new ZoneAwareLoadBalancer<>(config); - wrapServerList(balancer); balancer.setFilter(filter); return balancer; } @@ -95,20 +87,4 @@ public class RibbonClientConfiguration { return new RibbonLoadBalancerContext(loadBalancer, config); } - private void wrapServerList(ILoadBalancer balancer) { - if (balancer instanceof DynamicServerListLoadBalancer) { - @SuppressWarnings("unchecked") - DynamicServerListLoadBalancer dynamic = (DynamicServerListLoadBalancer) balancer; - ServerList list = dynamic.getServerListImpl(); - if (!(list instanceof DomainExtractingServerList)) { - // This is optional: you can use the native Eureka AWS features as long as - // the server zone is populated. TODO: verify that we back off if AWS - // metadata *is* available. - // @see com.netflix.appinfo.AmazonInfo.Builder - dynamic.setServerListImpl(new DomainExtractingServerList(list, dynamic - .getClientConfig(), this.approximateZoneFromHostname)); - } - } - } - } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/eureka/ZonePreferenceServerListFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/ZonePreferenceServerListFilter.java similarity index 97% rename from spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/eureka/ZonePreferenceServerListFilter.java rename to spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/ZonePreferenceServerListFilter.java index 389304b50..27e197f7e 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/eureka/ZonePreferenceServerListFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/ZonePreferenceServerListFilter.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.netflix.ribbon.eureka; +package org.springframework.cloud.netflix.ribbon; import java.util.ArrayList; import java.util.List; diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientConfiguration.java index d4bfc7e29..28fcf51c0 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/eureka/EurekaRibbonClientConfiguration.java @@ -18,8 +18,11 @@ package org.springframework.cloud.netflix.ribbon.eureka; import javax.annotation.PostConstruct; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter; import org.springframework.context.annotation.Configuration; import com.netflix.config.ConfigurationManager; @@ -27,6 +30,9 @@ import com.netflix.config.DeploymentContext.ContextKey; import com.netflix.config.DynamicPropertyFactory; import com.netflix.config.DynamicStringProperty; import com.netflix.discovery.EurekaClientConfig; +import com.netflix.loadbalancer.DynamicServerListLoadBalancer; +import com.netflix.loadbalancer.Server; +import com.netflix.loadbalancer.ServerList; import com.netflix.loadbalancer.ZoneAvoidanceRule; import com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList; @@ -45,7 +51,10 @@ import static com.netflix.client.config.CommonClientConfigKey.NIWSServerListFilt * @author Dave Syer */ @Configuration -public class EurekaRibbonClientConfiguration { +public class EurekaRibbonClientConfiguration implements BeanPostProcessor { + + @Value("${ribbon.eureka.approximateZoneFromHostname:false}") + private boolean approximateZoneFromHostname = false; @Value("${ribbon.client.name}") private String serviceId = "client"; @@ -92,6 +101,35 @@ public class EurekaRibbonClientConfiguration { setProp(this.serviceId, EnableZoneAffinity.key(), "true"); } + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + if (bean instanceof DynamicServerListLoadBalancer) { + wrapServerList((DynamicServerListLoadBalancer) bean); + } + return bean; + } + + private void wrapServerList(DynamicServerListLoadBalancer balancer) { + @SuppressWarnings("unchecked") + DynamicServerListLoadBalancer dynamic = (DynamicServerListLoadBalancer) balancer; + ServerList list = dynamic.getServerListImpl(); + if (!(list instanceof DomainExtractingServerList)) { + // This is optional: you can use the native Eureka AWS features as long as + // the server zone is populated. TODO: verify that we back off if AWS + // metadata *is* available. + // @see com.netflix.appinfo.AmazonInfo.Builder + dynamic.setServerListImpl(new DomainExtractingServerList(list, dynamic + .getClientConfig(), this.approximateZoneFromHostname)); + } + } + protected void setProp(String serviceId, String suffix, String value) { // how to set the namespace properly? String key = getKey(serviceId, suffix); diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/PlainRibbonClientPreprocessorIntegrationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/PlainRibbonClientPreprocessorIntegrationTests.java index 6233ac758..21b020d56 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/PlainRibbonClientPreprocessorIntegrationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/PlainRibbonClientPreprocessorIntegrationTests.java @@ -23,12 +23,12 @@ import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfigurati import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration; import org.springframework.cloud.netflix.ribbon.PlainRibbonClientPreprocessorIntegrationTests.TestConfiguration; -import org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList; 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.ConfigurationBasedServerList; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ZoneAwareLoadBalancer; @@ -44,17 +44,17 @@ public class PlainRibbonClientPreprocessorIntegrationTests { private SpringClientFactory factory; @Test - public void serverListIsWrapped() throws Exception { + public void serverListIsConfigured() throws Exception { @SuppressWarnings("unchecked") ZoneAwareLoadBalancer loadBalancer = (ZoneAwareLoadBalancer) this.factory .getLoadBalancer("foo"); - DomainExtractingServerList.class.cast(loadBalancer.getServerListImpl()); + ConfigurationBasedServerList.class.cast(loadBalancer.getServerListImpl()); } @Configuration @RibbonClient("foo") @Import({ PropertyPlaceholderAutoConfiguration.class, - ArchaiusAutoConfiguration.class, RibbonAutoConfiguration.class }) + ArchaiusAutoConfiguration.class, RibbonAutoConfiguration.class}) protected static class TestConfiguration { } diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientPreprocessorIntegrationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientPreprocessorIntegrationTests.java index 62ea4c5a9..0df53fa16 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientPreprocessorIntegrationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientPreprocessorIntegrationTests.java @@ -16,15 +16,15 @@ package org.springframework.cloud.netflix.ribbon; +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.ribbon.RibbonClientPreprocessorIntegrationTests.TestConfiguration; -import org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList; -import org.springframework.cloud.netflix.ribbon.eureka.ZonePreferenceServerListFilter; +import org.springframework.cloud.netflix.ribbon.RibbonClientPreprocessorIntegrationTests.PlainConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -35,27 +35,17 @@ import com.netflix.loadbalancer.AvailabilityFilteringRule; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ZoneAwareLoadBalancer; -import static org.junit.Assert.assertEquals; - /** * @author Dave Syer */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = TestConfiguration.class) +@SpringApplicationConfiguration(classes = PlainConfiguration.class) @DirtiesContext public class RibbonClientPreprocessorIntegrationTests { @Autowired private SpringClientFactory factory; - @Test - public void serverListIsWrapped() throws Exception { - @SuppressWarnings("unchecked") - ZoneAwareLoadBalancer loadBalancer = (ZoneAwareLoadBalancer) this.factory - .getLoadBalancer("foo"); - DomainExtractingServerList.class.cast(loadBalancer.getServerListImpl()); - } - @Test public void ruleDefaultsToAvailability() throws Exception { @SuppressWarnings("unchecked") @@ -74,18 +64,11 @@ public class RibbonClientPreprocessorIntegrationTests { .getZone()); } - @Configuration - @RibbonClient("foo") - @Import({ PropertyPlaceholderAutoConfiguration.class, - ArchaiusAutoConfiguration.class, RibbonAutoConfiguration.class }) - protected static class PlainConfiguration { - } - @Configuration @RibbonClient(name = "foo", configuration = FooConfiguration.class) @Import({ PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class, RibbonAutoConfiguration.class }) - protected static class TestConfiguration { + protected static class PlainConfiguration { } @Configuration diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientsPreprocessorIntegrationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientsPreprocessorIntegrationTests.java index 4d3fb2395..67daf0ed0 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientsPreprocessorIntegrationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientsPreprocessorIntegrationTests.java @@ -26,7 +26,6 @@ import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; import org.springframework.cloud.netflix.ribbon.RibbonClientsPreprocessorIntegrationTests.TestConfiguration; import org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList; import org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration; -import org.springframework.cloud.netflix.ribbon.eureka.ZonePreferenceServerListFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/ZonePreferenceServerListFilterTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/ZonePreferenceServerListFilterTests.java similarity index 94% rename from spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/ZonePreferenceServerListFilterTests.java rename to spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/ZonePreferenceServerListFilterTests.java index 357b6dc30..776a03eda 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/ZonePreferenceServerListFilterTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/ZonePreferenceServerListFilterTests.java @@ -14,13 +14,14 @@ * limitations under the License. */ -package org.springframework.cloud.netflix.ribbon.eureka; +package org.springframework.cloud.netflix.ribbon; import java.util.Arrays; import java.util.List; import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter; import org.springframework.test.util.ReflectionTestUtils; import com.netflix.loadbalancer.Server; 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 000000000..afdb4c6f1 --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/eureka/RibbonClientPreprocessorIntegrationTests.java @@ -0,0 +1,103 @@ +/* + * 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.ribbon.RibbonAutoConfiguration; +import org.springframework.cloud.netflix.ribbon.RibbonClient; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter; +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) this.factory + .getLoadBalancer("foo"); + DomainExtractingServerList.class.cast(loadBalancer.getServerListImpl()); + } + + @Test + public void ruleDefaultsToAvoidance() throws Exception { + @SuppressWarnings("unchecked") + ZoneAwareLoadBalancer loadBalancer = (ZoneAwareLoadBalancer) this.factory + .getLoadBalancer("foo"); + ZoneAvoidanceRule.class.cast(loadBalancer.getRule()); + } + + @Test + public void serverListFilterOverride() throws Exception { + @SuppressWarnings("unchecked") + ZoneAwareLoadBalancer loadBalancer = (ZoneAwareLoadBalancer) this.factory + .getLoadBalancer("foo"); + assertEquals("myTestZone", + ZonePreferenceServerListFilter.class.cast(loadBalancer.getFilter()) + .getZone()); + } + + @Configuration + @RibbonClient("foo") + @Import({ PropertyPlaceholderAutoConfiguration.class, + ArchaiusAutoConfiguration.class, RibbonAutoConfiguration.class }) + protected static class PlainConfiguration { + } + + @Configuration + @RibbonClient(name = "foo", configuration = FooConfiguration.class) + @Import({ PropertyPlaceholderAutoConfiguration.class, + ArchaiusAutoConfiguration.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; + } + } + +}