Merge branch 'master' into feignclient
Conflicts: spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/SpringDecoderTests.java
This commit is contained in:
@@ -8,8 +8,11 @@ import static com.netflix.config.ConfigurationManager.ENV_CONFIG_NAME;
|
||||
import static com.netflix.config.ConfigurationManager.SYS_CONFIG_NAME;
|
||||
import static com.netflix.config.ConfigurationManager.URL_CONFIG_NAME;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.commons.configuration.ConfigurationBuilder;
|
||||
import org.apache.commons.configuration.EnvironmentConfiguration;
|
||||
import org.apache.commons.configuration.SystemConfiguration;
|
||||
@@ -20,85 +23,111 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.netflix.config.ConcurrentCompositeConfiguration;
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import com.netflix.config.DynamicPropertyFactory;
|
||||
import com.netflix.config.DynamicURLConfiguration;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ConcurrentCompositeConfiguration.class, ConfigurationBuilder.class})
|
||||
@ConditionalOnClass({ ConcurrentCompositeConfiguration.class, ConfigurationBuilder.class })
|
||||
public class ArchaiusAutoConfiguration {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ArchaiusAutoConfiguration.class);
|
||||
private static final AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger(ArchaiusAutoConfiguration.class);
|
||||
private static final AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment env;
|
||||
@Autowired
|
||||
private ConfigurableEnvironment env;
|
||||
|
||||
@Bean
|
||||
public ConfigurableEnvironmentConfiguration configurableEnvironmentConfiguration() {
|
||||
ConfigurableEnvironmentConfiguration envConfig = new ConfigurableEnvironmentConfiguration(env);
|
||||
configureArchaius(envConfig);
|
||||
return envConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected ArchaiusEndpoint archaiusEndpoint() {
|
||||
return new ArchaiusEndpoint();
|
||||
}
|
||||
@PreDestroy
|
||||
public void close() {
|
||||
setStatic(ConfigurationManager.class, "instance", null);
|
||||
setStatic(ConfigurationManager.class, "customConfigurationInstalled", false);
|
||||
setStatic(DynamicPropertyFactory.class, "config", null);
|
||||
setStatic(DynamicPropertyFactory.class, "initializedWithDefaultConfig", false);
|
||||
initialized.compareAndSet(true, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Bean
|
||||
public ConfigurableEnvironmentConfiguration configurableEnvironmentConfiguration() {
|
||||
ConfigurableEnvironmentConfiguration envConfig = new ConfigurableEnvironmentConfiguration(
|
||||
env);
|
||||
configureArchaius(envConfig);
|
||||
return envConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected ArchaiusEndpoint archaiusEndpoint() {
|
||||
return new ArchaiusEndpoint();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void configureArchaius(ConfigurableEnvironmentConfiguration envConfig) {
|
||||
if (initialized.compareAndSet(false, true)) {
|
||||
String appName = env.getProperty("spring.application.name");
|
||||
if (appName == null) {
|
||||
appName = "application";
|
||||
logger.warn("No spring.application.name found, defaulting to 'application'");
|
||||
}
|
||||
//this is deprecated, but currently it seams the only way to set it initially
|
||||
System.setProperty(DEPLOYMENT_APPLICATION_ID_PROPERTY, appName);
|
||||
if (initialized.compareAndSet(false, true)) {
|
||||
String appName = env.getProperty("spring.application.name");
|
||||
if (appName == null) {
|
||||
appName = "application";
|
||||
logger.warn("No spring.application.name found, defaulting to 'application'");
|
||||
}
|
||||
// this is deprecated, but currently it seams the only way to set it initially
|
||||
System.setProperty(DEPLOYMENT_APPLICATION_ID_PROPERTY, appName);
|
||||
|
||||
//TODO: support for other DeploymentContexts
|
||||
// TODO: support for other DeploymentContexts
|
||||
|
||||
ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration();
|
||||
ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration();
|
||||
|
||||
//support to add other Configurations (Jdbc, DynamoDb, Zookeeper, jclouds, etc...)
|
||||
/*if (factories != null && !factories.isEmpty()) {
|
||||
for (PropertiesSourceFactory factory: factories) {
|
||||
config.addConfiguration(factory.getConfiguration(), factory.getName());
|
||||
}
|
||||
}*/
|
||||
config.addConfiguration(envConfig, ConfigurableEnvironmentConfiguration.class.getSimpleName());
|
||||
// support to add other Configurations (Jdbc, DynamoDb, Zookeeper, jclouds,
|
||||
// etc...)
|
||||
/*
|
||||
* if (factories != null && !factories.isEmpty()) { for
|
||||
* (PropertiesSourceFactory factory: factories) {
|
||||
* config.addConfiguration(factory.getConfiguration(), factory.getName()); } }
|
||||
*/
|
||||
config.addConfiguration(envConfig,
|
||||
ConfigurableEnvironmentConfiguration.class.getSimpleName());
|
||||
|
||||
//below come from ConfigurationManager.createDefaultConfigInstance()
|
||||
DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration();
|
||||
try {
|
||||
config.addConfiguration(defaultURLConfig, URL_CONFIG_NAME);
|
||||
} catch (Throwable e) {
|
||||
logger.error("Cannot create config from " + defaultURLConfig, e);
|
||||
}
|
||||
// below come from ConfigurationManager.createDefaultConfigInstance()
|
||||
DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration();
|
||||
try {
|
||||
config.addConfiguration(defaultURLConfig, URL_CONFIG_NAME);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
logger.error("Cannot create config from " + defaultURLConfig, e);
|
||||
}
|
||||
|
||||
//TODO: sys/env above urls?
|
||||
if (!Boolean.getBoolean(DISABLE_DEFAULT_SYS_CONFIG)) {
|
||||
SystemConfiguration sysConfig = new SystemConfiguration();
|
||||
config.addConfiguration(sysConfig, SYS_CONFIG_NAME);
|
||||
}
|
||||
if (!Boolean.getBoolean(DISABLE_DEFAULT_ENV_CONFIG)) {
|
||||
EnvironmentConfiguration environmentConfiguration = new EnvironmentConfiguration();
|
||||
config.addConfiguration(environmentConfiguration, ENV_CONFIG_NAME);
|
||||
}
|
||||
// TODO: sys/env above urls?
|
||||
if (!Boolean.getBoolean(DISABLE_DEFAULT_SYS_CONFIG)) {
|
||||
SystemConfiguration sysConfig = new SystemConfiguration();
|
||||
config.addConfiguration(sysConfig, SYS_CONFIG_NAME);
|
||||
}
|
||||
if (!Boolean.getBoolean(DISABLE_DEFAULT_ENV_CONFIG)) {
|
||||
EnvironmentConfiguration environmentConfiguration = new EnvironmentConfiguration();
|
||||
config.addConfiguration(environmentConfiguration, ENV_CONFIG_NAME);
|
||||
}
|
||||
|
||||
ConcurrentCompositeConfiguration appOverrideConfig = new ConcurrentCompositeConfiguration();
|
||||
config.addConfiguration(appOverrideConfig, APPLICATION_PROPERTIES);
|
||||
config.setContainerConfigurationIndex(config.getIndexOfConfiguration(appOverrideConfig));
|
||||
ConcurrentCompositeConfiguration appOverrideConfig = new ConcurrentCompositeConfiguration();
|
||||
config.addConfiguration(appOverrideConfig, APPLICATION_PROPERTIES);
|
||||
config.setContainerConfigurationIndex(config
|
||||
.getIndexOfConfiguration(appOverrideConfig));
|
||||
|
||||
ConfigurationManager.install(config);
|
||||
}
|
||||
else {
|
||||
// TODO: reinstall ConfigurationManager
|
||||
logger.warn("Netflix ConfigurationManager has already been installed, unable to re-install");
|
||||
}
|
||||
}
|
||||
|
||||
private static void setStatic(Class<?> type, String name, Object value) {
|
||||
// Hack a private static field
|
||||
Field field = ReflectionUtils.findField(type, name);
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, null, value);
|
||||
}
|
||||
|
||||
ConfigurationManager.install(config);
|
||||
} else {
|
||||
//TODO: reinstall ConfigurationManager
|
||||
logger.warn("Netflix ConfigurationManager has already been installed, unable to re-install");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.archaius;
|
||||
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class ArchaiusDelegatingProxyUtils {
|
||||
|
||||
public static String APPLICATION_CONTEXT = ApplicationContext.class.getName();
|
||||
|
||||
public static <T> T getNamedInstance(Class<T> type, String name) {
|
||||
ApplicationContext context = (ApplicationContext) ConfigurationManager.getConfigInstance().getProperty(APPLICATION_CONTEXT);
|
||||
return context!=null && context.containsBean(name) ? context.getBean(name, type) : null;
|
||||
}
|
||||
|
||||
public static <T> T getInstanceWithPrefix(Class<T> type, String prefix) {
|
||||
String name = prefix + type.getSimpleName();
|
||||
return getNamedInstance(type, name);
|
||||
}
|
||||
|
||||
public static void addApplicationContext(ConfigurableApplicationContext context) {
|
||||
AbstractConfiguration config = ConfigurationManager.getConfigInstance();
|
||||
config .clearProperty(APPLICATION_CONTEXT);
|
||||
config.setProperty(APPLICATION_CONTEXT, context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -78,6 +78,7 @@ public class FeignConfiguration {
|
||||
|
||||
protected <T> T loadBalance(Feign.Builder builder, Class<T> type, String schemeName) {
|
||||
String name = URI.create(schemeName).getHost();
|
||||
// TODO: This should be transparent
|
||||
ribbonClientPreprocessor.preprocess(name);
|
||||
|
||||
if(ribbonClient != null) {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
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
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
@Documented
|
||||
@Import(RibbonClientConfigurationRegistrar.class)
|
||||
public @interface EnableRibbonClient {
|
||||
|
||||
RibbonClient[] value() default {};
|
||||
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.springframework.cloud.netflix.ribbon;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -16,7 +15,6 @@ import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.netflix.client.IClient;
|
||||
import com.netflix.loadbalancer.BaseLoadBalancer;
|
||||
|
||||
/**
|
||||
* Auto configuration for Ribbon (client side load balancing)
|
||||
@@ -25,15 +23,18 @@ import com.netflix.loadbalancer.BaseLoadBalancer;
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(IClient.class)
|
||||
@EnableRibbonClient
|
||||
@AutoConfigureAfter(EurekaClientAutoConfiguration.class)
|
||||
public class RibbonAutoConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<BaseLoadBalancer> balancers = Collections.emptyList();
|
||||
@Autowired(required=false)
|
||||
private List<RibbonClientSpecification> configurations = new ArrayList<>();
|
||||
|
||||
@Bean
|
||||
@Bean
|
||||
public SpringClientFactory springClientFactory() {
|
||||
return new SpringClientFactory();
|
||||
SpringClientFactory factory = new SpringClientFactory();
|
||||
factory.setConfigurations(configurations);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -48,8 +49,8 @@ public class RibbonAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(LoadBalancerClient.class)
|
||||
public LoadBalancerClient loadBalancerClient(RibbonClientPreprocessor clientPreprocessor) {
|
||||
return new RibbonLoadBalancerClient(clientPreprocessor, springClientFactory(), balancers);
|
||||
public LoadBalancerClient loadBalancerClient() {
|
||||
return new RibbonLoadBalancerClient(springClientFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RibbonClient {
|
||||
String name();
|
||||
Class<?>[] configuration() default {};
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.netflix.client.config.DefaultClientConfigImpl;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
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.ZoneAffinityServerListFilter;
|
||||
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
|
||||
import com.netflix.niws.client.http.RestClient;
|
||||
import com.netflix.servo.monitor.Monitors;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Configuration
|
||||
@EnableConfigurationProperties
|
||||
public class RibbonClientConfiguration {
|
||||
|
||||
@Value("${ribbon.client.name}")
|
||||
private String name = "client";
|
||||
|
||||
@Autowired(required = false)
|
||||
private EurekaClientConfig eurekaClientConfig;
|
||||
|
||||
@Autowired(required = false)
|
||||
private RibbonClientPreprocessor preprocessor;
|
||||
|
||||
// TODO: maybe re-instate autowired load balancers: identified by name they could be
|
||||
// associated with ribbon clients
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (preprocessor!=null) {
|
||||
preprocessor.preprocess(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public IClientConfig ribbonClientConfig() {
|
||||
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
|
||||
config.loadProperties(name);
|
||||
return config;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RestClient ribbonRestClient(IClientConfig config, ILoadBalancer loadBalancer) {
|
||||
RestClient client = new RestClient(config);
|
||||
client.setLoadBalancer(loadBalancer);
|
||||
Monitors.registerObject("Client_" + name, client);
|
||||
return client;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerListFilter<Server> filter) {
|
||||
ZoneAwareLoadBalancer<Server> balancer = new ZoneAwareLoadBalancer<Server>(config);
|
||||
wrapServerList(balancer);
|
||||
balancer.setFilter(filter);
|
||||
return balancer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
|
||||
return new ZoneAffinityServerListFilter<Server>(config);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RibbonLoadBalancerContext ribbonLoadBalancerContext(ILoadBalancer loadBalancer, IClientConfig config) {
|
||||
return new RibbonLoadBalancerContext(loadBalancer, config);
|
||||
}
|
||||
|
||||
private void wrapServerList(ILoadBalancer balancer) {
|
||||
if (balancer instanceof DynamicServerListLoadBalancer) {
|
||||
@SuppressWarnings("unchecked")
|
||||
DynamicServerListLoadBalancer<Server> dynamic = (DynamicServerListLoadBalancer<Server>) balancer;
|
||||
ServerList<Server> 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class RibbonClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata metadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
Map<String, Object> attrs = metadata.getAnnotationAttributes(
|
||||
EnableRibbonClient.class.getName(), true);
|
||||
if (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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class RibbonClientSpecification {
|
||||
|
||||
private String name;
|
||||
private Class<?>[] configuration;
|
||||
|
||||
}
|
||||
@@ -1,20 +1,17 @@
|
||||
package org.springframework.cloud.netflix.ribbon;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.netflix.loadbalancer.BaseLoadBalancer;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerStats;
|
||||
import com.netflix.servo.monitor.Stopwatch;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerStats;
|
||||
import com.netflix.servo.monitor.Stopwatch;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -22,25 +19,16 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
|
||||
private RibbonClientPreprocessor ribbonClientPreprocessor;
|
||||
|
||||
private SpringClientFactory clientFactory;
|
||||
|
||||
private Map<String, ILoadBalancer> balancers = new ConcurrentHashMap<>();
|
||||
private Map<String, RibbonLoadBalancerContext> contexts = new ConcurrentHashMap<>();
|
||||
|
||||
public RibbonLoadBalancerClient(RibbonClientPreprocessor ribbonClientPreprocessor, SpringClientFactory clientFactory, List<BaseLoadBalancer> balancers) {
|
||||
this.ribbonClientPreprocessor = ribbonClientPreprocessor;
|
||||
public RibbonLoadBalancerClient(SpringClientFactory clientFactory) {
|
||||
this.clientFactory = clientFactory;
|
||||
for (BaseLoadBalancer balancer : balancers) {
|
||||
this.balancers.put(balancer.getName(), balancer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI reconstructURI(ServiceInstance instance, URI original) {
|
||||
String serviceId = instance.getServiceId();
|
||||
RibbonLoadBalancerContext context = getOrCreateLoadBalancerContext(serviceId, getLoadBalancer(serviceId));
|
||||
RibbonLoadBalancerContext context = clientFactory.getLoadBalancerContext(serviceId);
|
||||
Server server = new Server(instance.getHost(), instance.getPort());
|
||||
return context.reconstructURIWithServer(server, original);
|
||||
}
|
||||
@@ -53,7 +41,7 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
@Override
|
||||
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) {
|
||||
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
|
||||
RibbonLoadBalancerContext context = getOrCreateLoadBalancerContext(serviceId, loadBalancer);
|
||||
RibbonLoadBalancerContext context = clientFactory.getLoadBalancerContext(serviceId);
|
||||
Server server = getServer(serviceId, loadBalancer);
|
||||
RibbonServer ribbonServer = new RibbonServer(serviceId, server);
|
||||
|
||||
@@ -79,18 +67,10 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
context.noteRequestCompletion(serverStats, entity, exception, duration, null/*errorHandler*/);
|
||||
}
|
||||
|
||||
protected RibbonLoadBalancerContext getOrCreateLoadBalancerContext(String serviceId, ILoadBalancer loadBalancer) {
|
||||
RibbonLoadBalancerContext context = contexts.get(serviceId);
|
||||
if (context == null) {
|
||||
context = new RibbonLoadBalancerContext(loadBalancer);
|
||||
contexts.put(serviceId, context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
protected Server getServer(String serviceId) {
|
||||
return getServer(serviceId, getLoadBalancer(serviceId));
|
||||
}
|
||||
|
||||
protected Server getServer(String serviceId, ILoadBalancer loadBalancer) {
|
||||
Server server = loadBalancer.chooseServer("default");
|
||||
if (server == null) {
|
||||
@@ -101,12 +81,7 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
}
|
||||
|
||||
protected ILoadBalancer getLoadBalancer(String serviceId) {
|
||||
ribbonClientPreprocessor.preprocess(serviceId);
|
||||
ILoadBalancer loadBalancer = this.balancers.get(serviceId);
|
||||
if (loadBalancer == null) {
|
||||
loadBalancer = clientFactory.getNamedLoadBalancer(serviceId);
|
||||
}
|
||||
return loadBalancer;
|
||||
return clientFactory.getLoadBalancer(serviceId);
|
||||
}
|
||||
|
||||
protected static class RibbonServer implements ServiceInstance {
|
||||
|
||||
@@ -1,238 +1,153 @@
|
||||
package org.springframework.cloud.netflix.ribbon;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
import com.netflix.client.AbstractLoadBalancerAwareClient;
|
||||
import com.netflix.client.ClientException;
|
||||
import com.netflix.client.IClient;
|
||||
import com.netflix.client.IClientConfigAware;
|
||||
import com.netflix.client.config.CommonClientConfigKey;
|
||||
import com.netflix.client.config.DefaultClientConfigImpl;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.servo.monitor.Monitors;
|
||||
|
||||
/**
|
||||
* A factory that creates client, load balancer and client configuration instances from properties. It also keeps mappings of client names to
|
||||
* the created instances.
|
||||
* A factory that creates client, load balancer and client configuration instances. It
|
||||
* creates a Spring ApplicationContext per client name, and extracts the beans that it
|
||||
* needs from there.
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
public class SpringClientFactory {
|
||||
public class SpringClientFactory implements DisposableBean, ApplicationContextAware {
|
||||
|
||||
private Map<String, IClient<?,?>> simpleClientMap = new ConcurrentHashMap<>();
|
||||
private Map<String, ILoadBalancer> namedLBMap = new ConcurrentHashMap<>();
|
||||
private ConcurrentHashMap<String, IClientConfig> namedConfig = new ConcurrentHashMap<>();
|
||||
private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
|
||||
private Map<String, RibbonClientSpecification> configurations = new ConcurrentHashMap<>();
|
||||
private ApplicationContext parent;
|
||||
|
||||
/**
|
||||
* Utility method to create client and load balancer (if enabled in client config) given the name and client config.
|
||||
* Instances are created using reflection (see {@link #instantiateInstanceWithClientConfig(String, IClientConfig)}
|
||||
*
|
||||
* @param restClientName
|
||||
* @param clientConfig
|
||||
* @throws ClientException if any errors occurs in the process, or if the client with the same name already exists
|
||||
*/
|
||||
public synchronized IClient<?, ?> registerClientFromProperties(String restClientName, IClientConfig clientConfig) throws ClientException {
|
||||
IClient<?, ?> client;
|
||||
ILoadBalancer loadBalancer = null;
|
||||
if (simpleClientMap.get(restClientName) != null) {
|
||||
throw new ClientException(
|
||||
ClientException.ErrorType.GENERAL,
|
||||
"A Rest Client with this name is already registered. Please use a different name");
|
||||
}
|
||||
try {
|
||||
String clientClassName = (String) clientConfig.get(CommonClientConfigKey.ClientClassName);
|
||||
client = (IClient<?, ?>) instantiateInstanceWithClientConfig(clientClassName, clientConfig);
|
||||
boolean initializeNFLoadBalancer = Boolean.parseBoolean(clientConfig.get(
|
||||
CommonClientConfigKey.InitializeNFLoadBalancer, DefaultClientConfigImpl.DEFAULT_ENABLE_LOADBALANCER).toString());
|
||||
if (initializeNFLoadBalancer) {
|
||||
loadBalancer = getNamedLoadBalancer(restClientName, clientConfig.getClass());
|
||||
}
|
||||
if (client instanceof AbstractLoadBalancerAwareClient) {
|
||||
((AbstractLoadBalancerAwareClient<?,?>) client).setLoadBalancer(loadBalancer);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
String message = "Unable to InitializeAndAssociateNFLoadBalancer set for RestClient:"
|
||||
+ restClientName;
|
||||
log.warn(message);
|
||||
throw new ClientException(ClientException.ErrorType.CONFIGURATION,
|
||||
message, e);
|
||||
}
|
||||
simpleClientMap.put(restClientName, client);
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext parent) throws BeansException {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void setConfigurations(List<RibbonClientSpecification> configurations) {
|
||||
for (RibbonClientSpecification client : configurations) {
|
||||
this.configurations.put(client.getName(), client);
|
||||
}
|
||||
}
|
||||
|
||||
Monitors.registerObject("Client_" + restClientName, client);
|
||||
@Override
|
||||
public void destroy() {
|
||||
Collection<AnnotationConfigApplicationContext> values = contexts.values();
|
||||
contexts.clear();
|
||||
for (AnnotationConfigApplicationContext context : values) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Client Registered:" + client.toString());
|
||||
return client;
|
||||
}
|
||||
/**
|
||||
* Get the rest client associated with the name.
|
||||
*
|
||||
* @throws RuntimeException if any error occurs
|
||||
*/
|
||||
public <C extends IClient<?, ?>> C getClient(String name, Class<C> clientClass) {
|
||||
return getInstance(name, clientClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the named client from map if already created. Otherwise creates the client using the configuration returned by {@link #getNamedConfig(String)}.
|
||||
*
|
||||
* @throws RuntimeException if an error occurs in creating the client.
|
||||
*/
|
||||
public synchronized IClient<?,?> getNamedClient(String name) {
|
||||
return getNamedClient(name, DefaultClientConfigImpl.class);
|
||||
}
|
||||
/**
|
||||
* Get the load balancer associated with the name.
|
||||
*
|
||||
* @throws RuntimeException if any error occurs
|
||||
*/
|
||||
public ILoadBalancer getLoadBalancer(String name) {
|
||||
return getInstance(name, ILoadBalancer.class);
|
||||
}
|
||||
|
||||
public synchronized <C extends IClient<?,?>> C namedClient(String name, Class<C> clientClass) {
|
||||
return clientClass.cast(getNamedClient(name, DefaultClientConfigImpl.class));
|
||||
}
|
||||
/**
|
||||
* Get the load balancer context associated with the name.
|
||||
*
|
||||
* @throws RuntimeException if any error occurs
|
||||
*/
|
||||
public RibbonLoadBalancerContext getLoadBalancerContext(String serviceId) {
|
||||
return getInstance(serviceId, RibbonLoadBalancerContext.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the named client from map if already created. Otherwise creates the client using the configuration returned by {@link #createNamedClient(String, Class)}.
|
||||
*
|
||||
* @throws RuntimeException if an error occurs in creating the client.
|
||||
*/
|
||||
public synchronized IClient<?,?> getNamedClient(String name, Class<? extends IClientConfig> configClass) {
|
||||
if (simpleClientMap.get(name) != null) {
|
||||
return simpleClientMap.get(name);
|
||||
}
|
||||
try {
|
||||
return createNamedClient(name, configClass);
|
||||
} catch (ClientException e) {
|
||||
throw new RuntimeException("Unable to create client", e);
|
||||
}
|
||||
}
|
||||
private AnnotationConfigApplicationContext getContext(String name) {
|
||||
if (!contexts.containsKey(name)) {
|
||||
synchronized (contexts) {
|
||||
if (!contexts.containsKey(name)) {
|
||||
contexts.put(name, createContext(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
return contexts.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a named client using a IClientConfig instance created off the configClass class object passed in as the parameter.
|
||||
*
|
||||
* @throws ClientException if any error occurs, or if the client with the same name already exists
|
||||
*/
|
||||
public synchronized IClient<?,?> createNamedClient(String name, Class<? extends IClientConfig> configClass) throws ClientException {
|
||||
IClientConfig config = getNamedConfig(name, configClass);
|
||||
return registerClientFromProperties(name, config);
|
||||
}
|
||||
private AnnotationConfigApplicationContext createContext(String name) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
if (configurations.containsKey(name)) {
|
||||
for (Class<?> configuration : configurations.get(name).getConfiguration()) {
|
||||
context.register(configuration);
|
||||
}
|
||||
}
|
||||
context.register(PropertyPlaceholderAutoConfiguration.class,
|
||||
RibbonClientConfiguration.class);
|
||||
context.getEnvironment()
|
||||
.getPropertySources()
|
||||
.addFirst(
|
||||
new MapPropertySource("ribbon",
|
||||
Collections.<String, Object> singletonMap(
|
||||
"ribbon.client.name", name)));
|
||||
if (parent != null) {
|
||||
// Uses Environment from parent as well as beans
|
||||
context.setParent(parent);
|
||||
}
|
||||
context.refresh();
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the load balancer associated with the name, or create one with an instance {@link DefaultClientConfigImpl} if does not exist
|
||||
*
|
||||
* @throws RuntimeException if any error occurs
|
||||
*/
|
||||
public synchronized ILoadBalancer getNamedLoadBalancer(String name) {
|
||||
return getNamedLoadBalancer(name, DefaultClientConfigImpl.class);
|
||||
}
|
||||
private <C> C instantiateWithConfig(AnnotationConfigApplicationContext context,
|
||||
Class<C> clazz, IClientConfig config) {
|
||||
C result = null;
|
||||
if (IClientConfigAware.class.isAssignableFrom(clazz)) {
|
||||
IClientConfigAware obj = (IClientConfigAware) BeanUtils.instantiate(clazz);
|
||||
obj.initWithNiwsConfig(config);
|
||||
@SuppressWarnings("unchecked")
|
||||
C value = (C) obj;
|
||||
result = value;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
if (clazz.getConstructor(IClientConfig.class) != null) {
|
||||
result = clazz.getConstructor(IClientConfig.class)
|
||||
.newInstance(config);
|
||||
}
|
||||
else {
|
||||
result = BeanUtils.instantiate(clazz);
|
||||
}
|
||||
}
|
||||
catch (Throwable e) { // NOPMD
|
||||
}
|
||||
}
|
||||
context.getAutowireCapableBeanFactory().autowireBean(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the load balancer associated with the name, or create one with an instance of configClass if does not exist
|
||||
*
|
||||
* @throws RuntimeException if any error occurs
|
||||
* @see #registerNamedLoadBalancerFromProperties(String, Class)
|
||||
*/
|
||||
public synchronized ILoadBalancer getNamedLoadBalancer(String name, Class<? extends IClientConfig> configClass) {
|
||||
ILoadBalancer lb = namedLBMap.get(name);
|
||||
if (lb != null) {
|
||||
return lb;
|
||||
} else {
|
||||
try {
|
||||
lb = registerNamedLoadBalancerFromProperties(name, configClass);
|
||||
} catch (ClientException e) {
|
||||
throw new RuntimeException("Unable to create load balancer", e);
|
||||
}
|
||||
return lb;
|
||||
}
|
||||
}
|
||||
private <C> C getInstance(String name, Class<C> type) {
|
||||
AnnotationConfigApplicationContext context = getContext(name);
|
||||
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0) {
|
||||
return context.getBean(type);
|
||||
}
|
||||
IClientConfig config = getInstance(name, IClientConfig.class);
|
||||
return instantiateWithConfig(context, type, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and register a load balancer with the name and given the class of configClass.
|
||||
*
|
||||
* @throws ClientException if load balancer with the same name already exists or any error occurs
|
||||
* @see #instantiateInstanceWithClientConfig(String, IClientConfig)
|
||||
*/
|
||||
public ILoadBalancer registerNamedLoadBalancerFromclientConfig(String name, IClientConfig clientConfig) throws ClientException {
|
||||
if (namedLBMap.get(name) != null) {
|
||||
throw new ClientException("LoadBalancer for name " + name + " already exists");
|
||||
}
|
||||
ILoadBalancer lb = null;
|
||||
try {
|
||||
String loadBalancerClassName = (String) clientConfig.get(CommonClientConfigKey.NFLoadBalancerClassName);
|
||||
lb = (ILoadBalancer) instantiateInstanceWithClientConfig(loadBalancerClassName, clientConfig);
|
||||
namedLBMap.put(name, lb);
|
||||
log.info("Client:" + name
|
||||
+ " instantiated a LoadBalancer:" + lb.toString());
|
||||
return lb;
|
||||
} catch (Exception e) {
|
||||
throw new ClientException("Unable to instantiate/associate LoadBalancer with Client:" + name, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and register a load balancer with the name and given the class of configClass.
|
||||
*
|
||||
* @throws ClientException if load balancer with the same name already exists or any error occurs
|
||||
* @see #instantiateInstanceWithClientConfig(String, IClientConfig)
|
||||
*/
|
||||
public synchronized ILoadBalancer registerNamedLoadBalancerFromProperties(String name, Class<? extends IClientConfig> configClass) throws ClientException {
|
||||
if (namedLBMap.get(name) != null) {
|
||||
throw new ClientException("LoadBalancer for name " + name + " already exists");
|
||||
}
|
||||
IClientConfig clientConfig = getNamedConfig(name, configClass);
|
||||
return registerNamedLoadBalancerFromclientConfig(name, clientConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates instance related to client framework using reflection. It first checks if the object is an instance of
|
||||
* {@link IClientConfigAware} and if so invoke {@link IClientConfigAware#initWithNiwsConfig(IClientConfig)}. If that does not
|
||||
* apply, it tries to find if there is a constructor with {@link IClientConfig} as a parameter and if so invoke that constructor. If neither applies,
|
||||
* it simply invokes the no-arg constructor and ignores the clientConfig parameter.
|
||||
*
|
||||
* @param className Class name of the object
|
||||
* @param clientConfig IClientConfig object used for initialization.
|
||||
*/
|
||||
public Object instantiateInstanceWithClientConfig(String className, IClientConfig clientConfig)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
Class<?> clazz = Class.forName(className);
|
||||
if (IClientConfigAware.class.isAssignableFrom(clazz)) {
|
||||
IClientConfigAware obj = (IClientConfigAware) clazz.newInstance();
|
||||
obj.initWithNiwsConfig(clientConfig);
|
||||
return obj;
|
||||
} else {
|
||||
try {
|
||||
if (clazz.getConstructor(IClientConfig.class) != null) {
|
||||
return clazz.getConstructor(IClientConfig.class).newInstance(clientConfig);
|
||||
}
|
||||
} catch (Throwable e) { // NOPMD
|
||||
}
|
||||
}
|
||||
log.warn("Class " + className + " neither implements IClientConfigAware nor provides a constructor with IClientConfig as the parameter. Only default constructor will be used.");
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client configuration given the name or create one with {@link DefaultClientConfigImpl} if it does not exist.
|
||||
*
|
||||
* @see #getNamedConfig(String, Class)
|
||||
*/
|
||||
public IClientConfig getNamedConfig(String name) {
|
||||
return getNamedConfig(name, DefaultClientConfigImpl.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client configuration given the name or create one with clientConfigClass if it does not exist. An instance of IClientConfig
|
||||
* is created and {@link IClientConfig#loadProperties(String)} will be called.
|
||||
*/
|
||||
public IClientConfig getNamedConfig(String name, Class<? extends IClientConfig> clientConfigClass) {
|
||||
IClientConfig config = namedConfig.get(name);
|
||||
if (config != null) {
|
||||
return config;
|
||||
} else {
|
||||
try {
|
||||
config = clientConfigClass.newInstance();
|
||||
config.loadProperties(name);
|
||||
} catch (Throwable e) {
|
||||
log.error("Unable to create client config instance", e);
|
||||
return null;
|
||||
}
|
||||
config.loadProperties(name);
|
||||
IClientConfig old = namedConfig.putIfAbsent(name, config);
|
||||
if (old != null) {
|
||||
config = old;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,41 +6,34 @@ import static com.netflix.client.config.CommonClientConfigKey.NFLoadBalancerRule
|
||||
import static com.netflix.client.config.CommonClientConfigKey.NIWSServerListClassName;
|
||||
import static com.netflix.client.config.CommonClientConfigKey.NIWSServerListFilterClassName;
|
||||
|
||||
import com.netflix.config.DynamicPropertyFactory;
|
||||
import com.netflix.config.DynamicStringProperty;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClientPreprocessor;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
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.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
import com.netflix.loadbalancer.ZoneAvoidanceRule;
|
||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList;
|
||||
|
||||
/**
|
||||
* Preprocessor that configures defaults for eureka-discovered ribbon clients.
|
||||
* Such as: <code>@zone</code>, NIWSServerListClassName, DeploymentContextBasedVipAddresses,
|
||||
* NFLoadBalancerRuleClassName, NIWSServerListFilterClassName and more
|
||||
* Preprocessor that configures defaults for eureka-discovered ribbon clients. Such as:
|
||||
* <code>@zone</code>, NIWSServerListClassName, DeploymentContextBasedVipAddresses,
|
||||
* NFLoadBalancerRuleClassName, NIWSServerListFilterClassName and more
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class EurekaRibbonClientPreprocessor implements RibbonClientPreprocessor {
|
||||
|
||||
protected static final String VALUE_NOT_SET = "__not__set__";
|
||||
protected static final String DEFAULT_NAMESPACE = "ribbon";
|
||||
protected static final String VALUE_NOT_SET = "__not__set__";
|
||||
protected static final String DEFAULT_NAMESPACE = "ribbon";
|
||||
|
||||
private EurekaClientConfig clientConfig;
|
||||
private SpringClientFactory clientFactory;
|
||||
private EurekaClientConfig clientConfig;
|
||||
|
||||
public EurekaRibbonClientPreprocessor(EurekaClientConfig clientConfig, SpringClientFactory clientFactory) {
|
||||
public EurekaRibbonClientPreprocessor(EurekaClientConfig clientConfig) {
|
||||
this.clientConfig = clientConfig;
|
||||
this.clientFactory = clientFactory;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocess(String serviceId) {
|
||||
@@ -67,40 +60,23 @@ public class EurekaRibbonClientPreprocessor implements RibbonClientPreprocessor
|
||||
setProp(serviceId, NIWSServerListFilterClassName.key(),
|
||||
ZonePreferenceServerListFilter.class.getName());
|
||||
setProp(serviceId, EnableZoneAffinity.key(), "true");
|
||||
ILoadBalancer loadBalancer = clientFactory.getNamedLoadBalancer(serviceId);
|
||||
wrapServerList(loadBalancer);
|
||||
}
|
||||
|
||||
private void wrapServerList(ILoadBalancer balancer) {
|
||||
if (balancer instanceof DynamicServerListLoadBalancer) {
|
||||
@SuppressWarnings("unchecked")
|
||||
DynamicServerListLoadBalancer<Server> dynamic = (DynamicServerListLoadBalancer<Server>) balancer;
|
||||
ServerList<Server> 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: find a way to back off if AWS
|
||||
// metadata *is* available.
|
||||
// @see com.netflix.appinfo.AmazonInfo.Builder
|
||||
dynamic.setServerListImpl(new DomainExtractingServerList(list, dynamic.getClientConfig()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void setProp(String serviceId, String suffix, String value) {
|
||||
// how to set the namespace properly?
|
||||
String key = getKey(serviceId, suffix);
|
||||
DynamicStringProperty property = getProperty(key);
|
||||
if (property.get().equals(VALUE_NOT_SET)) {
|
||||
ConfigurationManager.getConfigInstance().setProperty(key, value);
|
||||
}
|
||||
String key = getKey(serviceId, suffix);
|
||||
DynamicStringProperty property = getProperty(key);
|
||||
if (property.get().equals(VALUE_NOT_SET)) {
|
||||
ConfigurationManager.getConfigInstance().setProperty(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
protected DynamicStringProperty getProperty(String key) {
|
||||
return DynamicPropertyFactory.getInstance().getStringProperty(key, VALUE_NOT_SET);
|
||||
}
|
||||
protected DynamicStringProperty getProperty(String key) {
|
||||
return DynamicPropertyFactory.getInstance().getStringProperty(key, VALUE_NOT_SET);
|
||||
}
|
||||
|
||||
protected String getKey(String serviceId, String suffix) {
|
||||
return serviceId + "." + DEFAULT_NAMESPACE + "." + suffix;
|
||||
}
|
||||
protected String getKey(String serviceId, String suffix) {
|
||||
return serviceId + "." + DEFAULT_NAMESPACE + "." + suffix;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClientPreprocessor;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@@ -46,7 +46,7 @@ public class RibbonEurekaAutoConfiguration {
|
||||
private EurekaClientConfig clientConfig;
|
||||
|
||||
@Bean
|
||||
public RibbonClientPreprocessor ribbonClientPreprocessor(SpringClientFactory clientFactory) {
|
||||
return new EurekaRibbonClientPreprocessor(clientConfig, clientFactory);
|
||||
public RibbonClientPreprocessor ribbonClientPreprocessor() {
|
||||
return new EurekaRibbonClientPreprocessor(clientConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ package org.springframework.cloud.netflix.ribbon.eureka;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import com.netflix.config.DeploymentContext.ContextKey;
|
||||
@@ -31,6 +34,8 @@ import com.netflix.loadbalancer.ZoneAffinityServerListFilter;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
public class ZonePreferenceServerListFilter extends ZoneAffinityServerListFilter<Server> {
|
||||
|
||||
private String zone;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package org.springframework.cloud.netflix.zuul;
|
||||
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* User: spencergibb
|
||||
* Date: 5/1/14
|
||||
* Time: 10:59 PM
|
||||
*/
|
||||
public abstract class SpringFilter extends ZuulFilter {
|
||||
|
||||
protected <T> T getBean(Class<T> beanClass) {
|
||||
//FIXME: hack because zuul uses servlet 2.5?
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof ServletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a servlet request");
|
||||
}
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttr;
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
|
||||
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
|
||||
return context.getBean(beanClass);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClientPreprocessor;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter;
|
||||
import org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter;
|
||||
import org.springframework.cloud.netflix.zuul.filters.pre.DebugFilter;
|
||||
@@ -34,6 +36,12 @@ public class ZuulConfiguration {
|
||||
@Autowired(required = false)
|
||||
private TraceRepository traces;
|
||||
|
||||
@Autowired
|
||||
private RibbonClientPreprocessor preprocessor;
|
||||
|
||||
@Autowired
|
||||
private SpringClientFactory clientFactory;
|
||||
|
||||
@Autowired
|
||||
private DiscoveryClient discovery;
|
||||
|
||||
@@ -93,7 +101,7 @@ public class ZuulConfiguration {
|
||||
// route filters
|
||||
@Bean
|
||||
public RibbonRoutingFilter ribbonRoutingFilter() {
|
||||
RibbonRoutingFilter filter = new RibbonRoutingFilter();
|
||||
RibbonRoutingFilter filter = new RibbonRoutingFilter(preprocessor, clientFactory);
|
||||
if (traces != null) {
|
||||
filter.setTraces(traces);
|
||||
}
|
||||
|
||||
@@ -17,9 +17,8 @@ import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClientPreprocessor;
|
||||
import org.springframework.cloud.netflix.zuul.SpringFilter;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.netflix.client.ClientException;
|
||||
@@ -27,12 +26,13 @@ import com.netflix.client.http.HttpRequest.Verb;
|
||||
import com.netflix.client.http.HttpResponse;
|
||||
import com.netflix.hystrix.exception.HystrixRuntimeException;
|
||||
import com.netflix.niws.client.http.RestClient;
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import com.netflix.zuul.exception.ZuulException;
|
||||
import com.netflix.zuul.util.HTTPRequestUtils;
|
||||
import com.sun.jersey.core.util.MultivaluedMapImpl;
|
||||
|
||||
public class RibbonRoutingFilter extends SpringFilter {
|
||||
public class RibbonRoutingFilter extends ZuulFilter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RibbonRoutingFilter.class);
|
||||
|
||||
@@ -40,6 +40,16 @@ public class RibbonRoutingFilter extends SpringFilter {
|
||||
|
||||
private TraceRepository traces;
|
||||
|
||||
private RibbonClientPreprocessor preprocessor;
|
||||
|
||||
private SpringClientFactory clientFactory;
|
||||
|
||||
public RibbonRoutingFilter(RibbonClientPreprocessor preprocessor,
|
||||
SpringClientFactory clientFactory) {
|
||||
this.preprocessor = preprocessor;
|
||||
this.clientFactory = clientFactory;
|
||||
}
|
||||
|
||||
public void setTraces(TraceRepository traces) {
|
||||
this.traces = traces;
|
||||
}
|
||||
@@ -71,10 +81,7 @@ public class RibbonRoutingFilter extends SpringFilter {
|
||||
|
||||
String serviceId = (String) context.get("serviceId");
|
||||
|
||||
getBean(RibbonClientPreprocessor.class).preprocess(serviceId);
|
||||
|
||||
//TODO: update to ribbon-rxnetty when available
|
||||
RestClient restClient = getBean(SpringClientFactory.class).namedClient(serviceId, RestClient.class);
|
||||
RestClient restClient = clientFactory.getClient(serviceId, RestClient.class);
|
||||
|
||||
String uri = request.getRequestURI();
|
||||
if (context.get("requestURI") != null) {
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.boot.test.EnvironmentTestUtils.addEnvironment;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
@@ -22,13 +25,9 @@ import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfigurati
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
|
||||
import com.netflix.appinfo.UniqueIdentifier;
|
||||
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.boot.test.EnvironmentTestUtils.*;
|
||||
import com.netflix.appinfo.UniqueIdentifier;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
@@ -11,6 +12,7 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
||||
@SpringApplicationConfiguration(classes = Application.class)
|
||||
@WebAppConfiguration
|
||||
@IntegrationTest("server.port=0")
|
||||
@DirtiesContext
|
||||
public class ApplicationTests {
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -29,7 +29,7 @@ import java.util.List;
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = SpringDecoderTests.Application.class)
|
||||
@WebAppConfiguration
|
||||
@IntegrationTest({ "server.port=0", "spring.application.name=springdecodertest" })
|
||||
@IntegrationTest({ "server.port=0", "spring.application.name=springdecodertest", "spring.jmx.enabled=true" })
|
||||
@DirtiesContext
|
||||
public class SpringDecoderTests extends FeignConfiguration {
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import static org.mockito.Mockito.*;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class RibbonInterceptorTest {
|
||||
public class RibbonInterceptorTests {
|
||||
|
||||
@Mock
|
||||
HttpRequest request;
|
||||
@@ -1,28 +1,34 @@
|
||||
package org.springframework.cloud.netflix.ribbon;
|
||||
|
||||
import com.netflix.loadbalancer.BaseLoadBalancer;
|
||||
import com.netflix.loadbalancer.LoadBalancerStats;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerStats;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.anyDouble;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.RibbonServer;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import com.netflix.loadbalancer.BaseLoadBalancer;
|
||||
import com.netflix.loadbalancer.LoadBalancerStats;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerStats;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class RibbonLoadBalancerClientTest {
|
||||
public class RibbonLoadBalancerClientTests {
|
||||
|
||||
@Mock
|
||||
RibbonClientPreprocessor preprocessor;
|
||||
@@ -42,6 +48,7 @@ public class RibbonLoadBalancerClientTest {
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
Mockito.when(clientFactory.getLoadBalancerContext(anyString())).thenReturn(new RibbonLoadBalancerContext(loadBalancer));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -122,11 +129,12 @@ public class RibbonLoadBalancerClientTest {
|
||||
}
|
||||
|
||||
protected RibbonLoadBalancerClient getRibbonLoadBalancerClient(RibbonServer ribbonServer) {
|
||||
when(loadBalancer.getName()).thenReturn(ribbonServer.getServiceId());
|
||||
when(loadBalancer.getName()).thenReturn(ribbonServer.getServiceId());
|
||||
when(loadBalancer.chooseServer(anyString())).thenReturn(ribbonServer.server);
|
||||
when(loadBalancer.getLoadBalancerStats()).thenReturn(loadBalancerStats);
|
||||
when(loadBalancerStats.getSingleServerStat(ribbonServer.server)).thenReturn(serverStats);
|
||||
when(clientFactory.getLoadBalancer(loadBalancer.getName())).thenReturn(loadBalancer);
|
||||
|
||||
return new RibbonLoadBalancerClient(preprocessor, clientFactory, Arrays.asList(loadBalancer));
|
||||
return new RibbonLoadBalancerClient(clientFactory);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||
import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
import com.netflix.client.DefaultLoadBalancerRetryHandler;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class SpringClientFactoryTests {
|
||||
|
||||
private SpringClientFactory factory = new SpringClientFactory();
|
||||
|
||||
@Test
|
||||
public void testConfigureRetry() {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(ArchaiusAutoConfiguration.class);
|
||||
EnvironmentTestUtils.addEnvironment(parent, "foo.ribbon.MaxAutoRetries:2");
|
||||
factory.setApplicationContext(parent);
|
||||
DefaultLoadBalancerRetryHandler retryHandler = (DefaultLoadBalancerRetryHandler) factory
|
||||
.getLoadBalancerContext("foo").getRetryHandler();
|
||||
assertEquals(2, retryHandler.getMaxRetriesOnSameServer());
|
||||
parent.close();
|
||||
factory.destroy();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,16 @@
|
||||
package org.springframework.cloud.netflix.ribbon.eureka;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.client.config.CommonClientConfigKey;
|
||||
@@ -7,14 +18,6 @@ import com.netflix.client.config.DefaultClientConfigImpl;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -64,7 +67,8 @@ public class DomainExtractingServerListTests {
|
||||
|
||||
protected DomainExtractingServerList getDomainExtractingServerList(DefaultClientConfigImpl config) {
|
||||
DiscoveryEnabledServer server = mock(DiscoveryEnabledServer.class);
|
||||
ServerList originalServerList = mock(ServerList.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
ServerList<Server> originalServerList = mock(ServerList.class);
|
||||
InstanceInfo instanceInfo = mock(InstanceInfo.class);
|
||||
|
||||
when(server.getInstanceInfo()).thenReturn(instanceInfo);
|
||||
@@ -75,7 +79,7 @@ public class DomainExtractingServerListTests {
|
||||
when(instanceInfo.getIPAddr()).thenReturn(IP_ADDR);
|
||||
when(instanceInfo.getPort()).thenReturn(PORT);
|
||||
|
||||
when(originalServerList.getInitialListOfServers()).thenReturn(Arrays.asList(server));
|
||||
when(originalServerList.getInitialListOfServers()).thenReturn(Arrays.<Server>asList(server));
|
||||
|
||||
return new DomainExtractingServerList(originalServerList, config);
|
||||
}
|
||||
|
||||
@@ -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.EnableRibbonClient;
|
||||
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.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 EurekaRibbonClientPreprocessorIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private SpringClientFactory factory;
|
||||
|
||||
@Test
|
||||
public void serverListIsWrapped() throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
ZoneAwareLoadBalancer<Server> loadBalancer = (ZoneAwareLoadBalancer<Server>) factory
|
||||
.getLoadBalancer("foo");
|
||||
DomainExtractingServerList.class.cast(loadBalancer.getServerListImpl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ruleDefaultsToZoneAvoidance() throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
ZoneAwareLoadBalancer<Server> loadBalancer = (ZoneAwareLoadBalancer<Server>) factory
|
||||
.getLoadBalancer("foo");
|
||||
ZoneAvoidanceRule.class.cast(loadBalancer.getRule());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverListFilterOverride() throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
ZoneAwareLoadBalancer<Server> loadBalancer = (ZoneAwareLoadBalancer<Server>) factory
|
||||
.getLoadBalancer("foo");
|
||||
assertEquals("myTestZone",
|
||||
ZonePreferenceServerListFilter.class.cast(loadBalancer.getFilter()).getZone());
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableRibbonClient(@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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,16 +18,16 @@ package org.springframework.cloud.netflix.ribbon.eureka;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.cloud.netflix.ribbon.eureka.EurekaRibbonClientPreprocessor.*;
|
||||
import static org.springframework.cloud.netflix.ribbon.eureka.EurekaRibbonClientPreprocessor.VALUE_NOT_SET;
|
||||
|
||||
import com.netflix.config.DynamicStringProperty;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import com.netflix.config.DeploymentContext.ContextKey;
|
||||
import com.netflix.config.DynamicStringProperty;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
|
||||
@@ -37,7 +37,7 @@ import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
|
||||
*
|
||||
*/
|
||||
public class EurekaRibbonClientPreprocessorTests {
|
||||
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone, "");
|
||||
@@ -47,40 +47,41 @@ public class EurekaRibbonClientPreprocessorTests {
|
||||
public void basicConfigurationCreatedForLoadBalancer() {
|
||||
EurekaClientConfigBean client = new EurekaClientConfigBean();
|
||||
client.getAvailabilityZones().put(client.getRegion(), "foo");
|
||||
SpringClientFactory clientFactory = new SpringClientFactory();
|
||||
EurekaRibbonClientPreprocessor clientPreprocessor = new EurekaRibbonClientPreprocessor(
|
||||
client, clientFactory);
|
||||
SpringClientFactory clientFactory = new SpringClientFactory();
|
||||
EurekaRibbonClientPreprocessor clientPreprocessor = new EurekaRibbonClientPreprocessor(
|
||||
client);
|
||||
clientPreprocessor.preprocess("service");
|
||||
ILoadBalancer balancer = clientFactory.getNamedLoadBalancer("service");
|
||||
ILoadBalancer balancer = clientFactory.getLoadBalancer("service");
|
||||
assertNotNull(balancer);
|
||||
@SuppressWarnings("unchecked")
|
||||
ZoneAwareLoadBalancer<Server> aware = (ZoneAwareLoadBalancer<Server>) balancer;
|
||||
assertTrue(aware.getServerListImpl() instanceof DomainExtractingServerList);
|
||||
assertEquals("foo", ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone));
|
||||
assertEquals("foo",
|
||||
ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetProp() {
|
||||
EurekaClientConfigBean client = new EurekaClientConfigBean();
|
||||
SpringClientFactory clientFactory = new SpringClientFactory();
|
||||
EurekaRibbonClientPreprocessor preprocessor = new EurekaRibbonClientPreprocessor(
|
||||
client, clientFactory);
|
||||
@Test
|
||||
public void testSetProp() {
|
||||
EurekaClientConfigBean client = new EurekaClientConfigBean();
|
||||
EurekaRibbonClientPreprocessor preprocessor = new EurekaRibbonClientPreprocessor(
|
||||
client);
|
||||
|
||||
String serviceId = "myService";
|
||||
String suffix = "mySuffix";
|
||||
String value = "myValue";
|
||||
String serviceId = "myService";
|
||||
String suffix = "mySuffix";
|
||||
String value = "myValue";
|
||||
|
||||
DynamicStringProperty property = preprocessor.getProperty(preprocessor.getKey(serviceId, suffix));
|
||||
DynamicStringProperty property = preprocessor.getProperty(preprocessor.getKey(
|
||||
serviceId, suffix));
|
||||
|
||||
assertEquals("property doesn't have default value", VALUE_NOT_SET, property.get());
|
||||
assertEquals("property doesn't have default value", VALUE_NOT_SET, property.get());
|
||||
|
||||
preprocessor.setProp(serviceId, suffix, value);
|
||||
preprocessor.setProp(serviceId, suffix, value);
|
||||
|
||||
assertEquals("property has wrong value", value, property.get());
|
||||
assertEquals("property has wrong value", value, property.get());
|
||||
|
||||
preprocessor.setProp(serviceId, suffix, value);
|
||||
preprocessor.setProp(serviceId, suffix, value);
|
||||
|
||||
assertEquals("property has wrong value", value, property.get());
|
||||
}
|
||||
assertEquals("property has wrong value", value, property.get());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
@@ -22,6 +23,7 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
||||
@IntegrationTest({ "server.port: 0",
|
||||
"zuul.routes.other: /test/**=http://localhost:7777/local",
|
||||
"zuul.routes.simple: /simple/**" })
|
||||
@DirtiesContext
|
||||
public class SampleZuulProxyApplicationTests {
|
||||
|
||||
@Value("${local.server.port}")
|
||||
|
||||
Reference in New Issue
Block a user