Adds ConfigData support for s.c.config.discovery.enabled=true
This commit is contained in:
@@ -16,18 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
import com.netflix.discovery.endpoint.EndpointUtils;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
import com.netflix.discovery.shared.resolver.DefaultEndpoint;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpResponse;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
@@ -38,11 +28,9 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaServiceInstance;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateTransportClientFactory;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientEurekaHttpClient;
|
||||
@@ -50,8 +38,6 @@ import org.springframework.cloud.netflix.eureka.http.WebClientTransportClientFac
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
@@ -61,13 +47,11 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@ConditionalOnClass(ConfigServicePropertySourceLocator.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = false)
|
||||
@ConditionalOnProperty("spring.cloud.config.discovery.enabled")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties
|
||||
public class EurekaConfigServerBootstrapConfiguration {
|
||||
|
||||
private static final Log log = LogFactory.getLog(EurekaConfigServerBootstrapConfiguration.class);
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT)
|
||||
public EurekaClientConfigBean eurekaClientConfigBean() {
|
||||
@@ -81,78 +65,13 @@ public class EurekaConfigServerBootstrapConfiguration {
|
||||
public RestTemplateEurekaHttpClient configDiscoveryRestTemplateEurekaHttpClient(EurekaClientConfigBean config,
|
||||
Environment env) {
|
||||
return (RestTemplateEurekaHttpClient) new RestTemplateTransportClientFactory()
|
||||
.newClient(new DefaultEndpoint(getEurekaUrl(config, env)));
|
||||
}
|
||||
|
||||
private static String getEurekaUrl(EurekaClientConfigBean config, Environment env) {
|
||||
List<String> urls = EndpointUtils.getDiscoveryServiceUrls(config, EurekaClientConfigBean.DEFAULT_ZONE,
|
||||
new HostnameBasedUrlRandomizer(env.getProperty("eureka.instance.hostname")));
|
||||
return urls.get(0);
|
||||
}
|
||||
|
||||
private boolean isSuccessful(EurekaHttpResponse<Applications> response) {
|
||||
HttpStatus httpStatus = HttpStatus.resolve(response.getStatusCode());
|
||||
return httpStatus != null && httpStatus.is2xxSuccessful();
|
||||
.newClient(HostnameBasedUrlRandomizer.randomEndpoint(config, env));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConfigServerInstanceProvider.Function eurekaConfigServerInstanceProvider(EurekaHttpClient client,
|
||||
EurekaClientConfig config) {
|
||||
|
||||
return serviceId -> {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("eurekaConfigServerInstanceProvider finding instances for " + serviceId);
|
||||
}
|
||||
EurekaHttpResponse<Applications> response = client.getApplications(config.getRegion());
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
if (!isSuccessful(response) || response.getEntity() == null) {
|
||||
return instances;
|
||||
}
|
||||
|
||||
Applications applications = response.getEntity();
|
||||
applications.shuffleInstances(config.shouldFilterOnlyUpInstances());
|
||||
List<InstanceInfo> infos = applications.getInstancesByVirtualHostName(serviceId);
|
||||
for (InstanceInfo info : infos) {
|
||||
instances.add(new EurekaServiceInstance(info));
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("eurekaConfigServerInstanceProvider found " + infos.size() + " instance(s) for " + serviceId
|
||||
+ ", " + instances);
|
||||
}
|
||||
return instances;
|
||||
};
|
||||
}
|
||||
|
||||
private static final class HostnameBasedUrlRandomizer implements EndpointUtils.ServiceUrlRandomizer {
|
||||
|
||||
private final String hostname;
|
||||
|
||||
private HostnameBasedUrlRandomizer(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomize(List<String> urlList) {
|
||||
int listSize = 0;
|
||||
if (urlList != null) {
|
||||
listSize = urlList.size();
|
||||
}
|
||||
if (!StringUtils.hasText(hostname) || listSize == 0) {
|
||||
return;
|
||||
}
|
||||
// Find the hashcode of the instance hostname and use it to find an entry
|
||||
// and then arrange the rest of the entries after this entry.
|
||||
int instanceHashcode = hostname.hashCode();
|
||||
if (instanceHashcode < 0) {
|
||||
instanceHashcode = instanceHashcode * -1;
|
||||
}
|
||||
int backupInstance = instanceHashcode % listSize;
|
||||
for (int i = 0; i < backupInstance; i++) {
|
||||
String zone = urlList.remove(0);
|
||||
urlList.add(zone);
|
||||
}
|
||||
}
|
||||
|
||||
return new EurekaConfigServerInstanceProvider(client, config)::getInstances;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -166,7 +85,7 @@ public class EurekaConfigServerBootstrapConfiguration {
|
||||
public WebClientEurekaHttpClient configDiscoveryWebClientEurekaHttpClient(EurekaClientConfigBean config,
|
||||
ObjectProvider<WebClient.Builder> builder, Environment env) {
|
||||
return (WebClientEurekaHttpClient) new WebClientTransportClientFactory(builder::getIfAvailable)
|
||||
.newClient(new DefaultEndpoint(getEurekaUrl(config, env)));
|
||||
.newClient(HostnameBasedUrlRandomizer.randomEndpoint(config, env));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.eureka.config;
|
||||
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
|
||||
import org.springframework.boot.BootstrapRegistry;
|
||||
import org.springframework.boot.Bootstrapper;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.cloud.config.client.ConfigClientProperties;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateTransportClientFactory;
|
||||
|
||||
public class EurekaConfigServerBootstrapper implements Bootstrapper {
|
||||
|
||||
@Override
|
||||
public void intitialize(BootstrapRegistry registry) {
|
||||
registry.registerIfAbsent(EurekaClientConfigBean.class, context -> {
|
||||
Binder binder = context.get(Binder.class);
|
||||
if (!getDiscoveryEnabled(binder)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return binder.bind(EurekaClientConfigBean.PREFIX, EurekaClientConfigBean.class)
|
||||
.orElseGet(EurekaClientConfigBean::new);
|
||||
});
|
||||
registry.registerIfAbsent(ConfigServerInstanceProvider.Function.class, context -> {
|
||||
Binder binder = context.get(Binder.class);
|
||||
if (!getDiscoveryEnabled(binder)) {
|
||||
return null;
|
||||
}
|
||||
EurekaClientConfigBean config = context.get(EurekaClientConfigBean.class);
|
||||
EurekaHttpClient httpClient = new RestTemplateTransportClientFactory()
|
||||
.newClient(HostnameBasedUrlRandomizer.randomEndpoint(config, binder));
|
||||
return new EurekaConfigServerInstanceProvider(httpClient, config)::getInstances;
|
||||
});
|
||||
}
|
||||
|
||||
private Boolean getDiscoveryEnabled(Binder binder) {
|
||||
return binder.bind(ConfigClientProperties.CONFIG_DISCOVERY_ENABLED, Boolean.class).orElse(false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.eureka.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpResponse;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaServiceInstance;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
public class EurekaConfigServerInstanceProvider {
|
||||
|
||||
private final Log log;
|
||||
|
||||
private final EurekaHttpClient client;
|
||||
|
||||
private final EurekaClientConfig config;
|
||||
|
||||
public EurekaConfigServerInstanceProvider(EurekaHttpClient client, EurekaClientConfig config) {
|
||||
this(LogFactory.getLog(EurekaConfigServerInstanceProvider.class), client, config);
|
||||
}
|
||||
|
||||
public EurekaConfigServerInstanceProvider(Log log, EurekaHttpClient client, EurekaClientConfig config) {
|
||||
this.log = log;
|
||||
this.client = client;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public List<ServiceInstance> getInstances(String serviceId) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("eurekaConfigServerInstanceProvider finding instances for " + serviceId);
|
||||
}
|
||||
EurekaHttpResponse<Applications> response = client.getApplications(config.getRegion());
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
if (!isSuccessful(response) || response.getEntity() == null) {
|
||||
return instances;
|
||||
}
|
||||
|
||||
Applications applications = response.getEntity();
|
||||
applications.shuffleInstances(config.shouldFilterOnlyUpInstances());
|
||||
List<InstanceInfo> infos = applications.getInstancesByVirtualHostName(serviceId);
|
||||
for (InstanceInfo info : infos) {
|
||||
instances.add(new EurekaServiceInstance(info));
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("eurekaConfigServerInstanceProvider found " + infos.size() + " instance(s) for " + serviceId
|
||||
+ ", " + instances);
|
||||
}
|
||||
return instances;
|
||||
}
|
||||
|
||||
private boolean isSuccessful(EurekaHttpResponse<Applications> response) {
|
||||
HttpStatus httpStatus = HttpStatus.resolve(response.getStatusCode());
|
||||
return httpStatus != null && httpStatus.is2xxSuccessful();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.eureka.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.discovery.endpoint.EndpointUtils;
|
||||
import com.netflix.discovery.shared.resolver.DefaultEndpoint;
|
||||
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
final class HostnameBasedUrlRandomizer implements EndpointUtils.ServiceUrlRandomizer {
|
||||
|
||||
private final String hostname;
|
||||
|
||||
HostnameBasedUrlRandomizer(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomize(List<String> urlList) {
|
||||
int listSize = 0;
|
||||
if (urlList != null) {
|
||||
listSize = urlList.size();
|
||||
}
|
||||
if (!StringUtils.hasText(hostname) || listSize == 0) {
|
||||
return;
|
||||
}
|
||||
// Find the hashcode of the instance hostname and use it to find an entry
|
||||
// and then arrange the rest of the entries after this entry.
|
||||
int instanceHashcode = hostname.hashCode();
|
||||
if (instanceHashcode < 0) {
|
||||
instanceHashcode = instanceHashcode * -1;
|
||||
}
|
||||
int backupInstance = instanceHashcode % listSize;
|
||||
for (int i = 0; i < backupInstance; i++) {
|
||||
String zone = urlList.remove(0);
|
||||
urlList.add(zone);
|
||||
}
|
||||
}
|
||||
|
||||
static String getEurekaUrl(EurekaClientConfigBean config, String hostname) {
|
||||
List<String> urls = EndpointUtils.getDiscoveryServiceUrls(config, EurekaClientConfigBean.DEFAULT_ZONE,
|
||||
new HostnameBasedUrlRandomizer(hostname));
|
||||
return urls.get(0);
|
||||
}
|
||||
|
||||
static DefaultEndpoint randomEndpoint(EurekaClientConfigBean config, Environment env) {
|
||||
String hostname = env.getProperty("eureka.instance.hostname");
|
||||
return new DefaultEndpoint(getEurekaUrl(config, hostname));
|
||||
}
|
||||
|
||||
static DefaultEndpoint randomEndpoint(EurekaClientConfigBean config, Binder binder) {
|
||||
String hostname = binder.bind("eureka.instance.hostname", String.class).orElseGet(() -> null);
|
||||
return new DefaultEndpoint(getEurekaUrl(config, hostname));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,3 +8,6 @@ org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancerEurekaAutoConf
|
||||
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapConfiguration
|
||||
|
||||
org.springframework.boot.Bootstrapper=\
|
||||
org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapper
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.eureka.config;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class EurekaConfigServerBootstrapperTests {
|
||||
|
||||
@Test
|
||||
public void notEnabledDoesNotAddInstanceProviderFn() {
|
||||
new SpringApplicationBuilder(TestConfig.class)
|
||||
.properties("spring.cloud.service-registry.auto-registration.enabled=false")
|
||||
.addBootstrapper(registry -> registry.addCloseListener(event -> {
|
||||
ConfigServerInstanceProvider.Function providerFn = event.getBootstrapContext()
|
||||
.get(ConfigServerInstanceProvider.Function.class);
|
||||
assertThat(providerFn).as("ConfigServerInstanceProvider.Function was created when it shouldn't")
|
||||
.isNull();
|
||||
})).run().close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enabledAddsInstanceProviderFn() {
|
||||
new SpringApplicationBuilder(TestConfig.class)
|
||||
.properties("spring.cloud.config.discovery.enabled=true",
|
||||
"spring.cloud.service-registry.auto-registration.enabled=false")
|
||||
.addBootstrapper(registry -> registry.addCloseListener(event -> {
|
||||
ConfigServerInstanceProvider.Function providerFn = event.getBootstrapContext()
|
||||
.get(ConfigServerInstanceProvider.Function.class);
|
||||
assertThat(providerFn).as("ConfigServerInstanceProvider.Function was not created when it should.")
|
||||
.isNotNull();
|
||||
})).run().close();
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
static class TestConfig {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user