diff --git a/pom.xml b/pom.xml index 69eeedce..583ad2db 100644 --- a/pom.xml +++ b/pom.xml @@ -210,7 +210,7 @@ 1.1.135 6.1.2 1.4.0-RC4 - 0.3.12 + 0.3.13 0.4 1.0.24 diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/ClientAutoConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/ClientAutoConfiguration.java new file mode 100644 index 00000000..0265a7ba --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/ClientAutoConfiguration.java @@ -0,0 +1,24 @@ +package org.springframework.cloud.client; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Spencer Gibb + * TODO: move org.springframework.cloud.client to a spring-cloud-common project + */ +@Configuration +@EnableConfigurationProperties +@ConditionalOnExpression("${spring.cloud.client.enabled:true}") +public class ClientAutoConfiguration { + + @Bean + @ConditionalOnMissingBean(ClientProperties.class) + public ClientProperties clientProperties() { + return new ClientProperties(); + } + +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/ClientProperties.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/ClientProperties.java new file mode 100644 index 00000000..bad73134 --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/ClientProperties.java @@ -0,0 +1,15 @@ +package org.springframework.cloud.client; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.List; + +/** + * @author Spencer Gibb + */ +@Data +@ConfigurationProperties("spring.cloud.client") +public class ClientProperties { + private List serviceIds; +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java index 2639e957..0126c7ec 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java @@ -19,6 +19,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.client.ClientProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -47,4 +48,9 @@ public class EurekaClientAutoConfiguration { return new EurekaInstanceConfigBean(); } + @Bean + @ConditionalOnMissingBean(EurekaRibbonInitializer.class) + public EurekaRibbonInitializer eurekaRibbonInitializer(ClientProperties clientProperties) { + return new EurekaRibbonInitializer(clientProperties); + } } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaRibbonInitializer.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaRibbonInitializer.java new file mode 100644 index 00000000..6ae141ae --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaRibbonInitializer.java @@ -0,0 +1,28 @@ +package org.springframework.cloud.netflix.eureka; + +import com.netflix.config.ConfigurationManager; +import com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList; +import org.springframework.cloud.client.ClientProperties; + +/** + * @author Spencer Gibb + */ +public class EurekaRibbonInitializer { + + public EurekaRibbonInitializer(ClientProperties clientProperties) { + if (clientProperties.getServiceIds() != null) { + for (String serviceId : clientProperties.getServiceIds()) { + setServiceListClassAndVIP(serviceId); + } + } + } + + public static void setServiceListClassAndVIP(String serviceId) { + setProp(serviceId, "NIWSServerListClassName", DiscoveryEnabledNIWSServerList.class.getName()); + setProp(serviceId, "DeploymentContextBasedVipAddresses", serviceId); //FIXME: what should this be? + } + + private static void setProp(String serviceId, String suffix, String value) { + ConfigurationManager.getConfigInstance().setProperty(serviceId + ".ribbon." + suffix, value); + } +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignConfigurer.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignConfigurer.java index 6ed017c7..3cc25ca3 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignConfigurer.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignConfigurer.java @@ -1,7 +1,5 @@ package org.springframework.cloud.netflix.feign; -import com.netflix.config.ConfigurationManager; -import com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList; import feign.Contract; import feign.Feign; import feign.Logger; @@ -50,16 +48,7 @@ public class FeignConfigurer { protected T loadBalance(Feign.Builder builder, Class type, String schemeName) { String name = URI.create(schemeName).getHost(); - setServiceListClassAndVIP(name); return builder.target(LoadBalancingTarget.create(type, schemeName)); } - public static void setServiceListClassAndVIP(String serviceId) { - setProp(serviceId, "NIWSServerListClassName", DiscoveryEnabledNIWSServerList.class.getName()); - setProp(serviceId, "DeploymentContextBasedVipAddresses", serviceId); //FIXME: what should this be? - } - - private static void setProp(String serviceId, String suffix, String value) { - ConfigurationManager.getConfigInstance().setProperty(serviceId + ".ribbon." + suffix, value); - } } 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 new file mode 100644 index 00000000..867c5141 --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java @@ -0,0 +1,45 @@ +package org.springframework.cloud.netflix.ribbon; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; +import org.springframework.cloud.netflix.eureka.EurekaRibbonInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Spencer Gibb + */ +@Configuration +@AutoConfigureAfter(EurekaClientAutoConfiguration.class) +public class RibbonAutoConfiguration { + + //TODO: why doesn't @AutoConfigureAfter(EurekaClientAutoConfiguration.class) do what the following does for order? + @Autowired + EurekaRibbonInitializer eurekaRibbonInitializer; + + @Bean + @ConditionalOnMissingBean(RestTemplate.class) + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + @Bean + public RibbonInterceptor ribbonInterceptor() { + return new RibbonInterceptor(); + } + + @PostConstruct + public void init() { + List list = new ArrayList<>(); + list.add(ribbonInterceptor()); + restTemplate().setInterceptors(list); + } +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonInterceptor.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonInterceptor.java new file mode 100644 index 00000000..2e5f119e --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonInterceptor.java @@ -0,0 +1,42 @@ +package org.springframework.cloud.netflix.ribbon; + +import com.netflix.client.ClientFactory; +import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.Server; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.support.HttpRequestWrapper; +import org.springframework.web.util.UriComponentsBuilder; + +import java.io.IOException; +import java.net.URI; + +/** + * @author Spencer Gibb + */ +public class RibbonInterceptor implements ClientHttpRequestInterceptor { + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { + HttpRequestWrapper wrapper = new HttpRequestWrapper(request) { + @Override + public URI getURI() { + URI originalUri = super.getURI(); + String serviceName = originalUri.getHost(); + ILoadBalancer loadBalancer = ClientFactory.getNamedLoadBalancer(serviceName); + Server server = loadBalancer.chooseServer(null); + if (server == null) { + throw new IllegalStateException("Unable to locate ILoadBalancer for service: "+ serviceName); + } + URI uri = UriComponentsBuilder.fromUri(originalUri) + .host(server.getHost()) + .port(server.getPort()) + .build() + .toUri(); + return uri; + } + }; + return execution.execute(wrapper, body); + } +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java index 0cf9fd18..f8cd7b8a 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java @@ -1,6 +1,6 @@ package org.springframework.cloud.netflix.zuul.filters.route; -import static org.springframework.cloud.netflix.feign.FeignConfigurer.setServiceListClassAndVIP; +import static org.springframework.cloud.netflix.eureka.EurekaRibbonInitializer.setServiceListClassAndVIP; import java.io.IOException; import java.io.InputStream; diff --git a/spring-cloud-netflix-core/src/main/resources/META-INF/spring.factories b/spring-cloud-netflix-core/src/main/resources/META-INF/spring.factories index ae83438b..73804c3e 100644 --- a/spring-cloud-netflix-core/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-netflix-core/src/main/resources/META-INF/spring.factories @@ -1,5 +1,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.springframework.cloud.client.ClientAutoConfiguration,\ org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration,\ org.springframework.cloud.netflix.feign.FeignAutoConfiguration,\ org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\ +org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration,\ org.springframework.cloud.netflix.servo.ServoMetricsAutoConfiguration \ No newline at end of file