Applied checkstyle and turned it on by default

This commit is contained in:
Marcin Grzejszczak
2019-02-01 12:50:02 +01:00
parent e024f6f5c2
commit ae314100f5
313 changed files with 8658 additions and 4416 deletions

View File

@@ -37,4 +37,4 @@ jobs:
destination: artifacts
- store_test_results:
path: ~/junit/
destination: testartifacts
destination: testartifacts

14
.editorconfig Normal file
View File

@@ -0,0 +1,14 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = tab
indent_size = 4
end_of_line = lf
insert_final_newline = true
[*.yml]
indent_style = space
indent_size = 2

View File

@@ -1,66 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<settings>
<servers>
<server>
<id>repo.spring.io</id>
<username>${env.CI_DEPLOY_USERNAME}</username>
<password>${env.CI_DEPLOY_PASSWORD}</password>
</server>
</servers>
<profiles>
<profile>
<!--
N.B. this profile is only here to support users and IDEs that do not use Maven 3.3.
It isn't needed on the command line if you use the wrapper script (mvnw) or if you use
a native Maven with the right version. Eclipse users should points their Maven tooling to
this settings file, or copy the profile into their ~/.m2/settings.xml.
-->
<id>spring</id>
<activation><activeByDefault>true</activeByDefault></activation>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<servers>
<server>
<id>repo.spring.io</id>
<username>${env.CI_DEPLOY_USERNAME}</username>
<password>${env.CI_DEPLOY_PASSWORD}</password>
</server>
</servers>
<profiles>
<profile>
<!--
N.B. this profile is only here to support users and IDEs that do not use Maven 3.3.
It isn't needed on the command line if you use the wrapper script (mvnw) or if you use
a native Maven with the right version. Eclipse users should points their Maven tooling to
this settings file, or copy the profile into their ~/.m2/settings.xml.
-->
<id>spring</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
</settings>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

40
pom.xml
View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons-parent</artifactId>
@@ -16,12 +18,18 @@
</parent>
<scm>
<url>https://github.com/spring-cloud/spring-cloud-commons</url>
<connection>scm:git:git://github.com/spring-cloud/spring-cloud-commons.git</connection>
<developerConnection>scm:git:ssh://git@github.com/spring-cloud/spring-cloud-commons.git</developerConnection>
<connection>scm:git:git://github.com/spring-cloud/spring-cloud-commons.git
</connection>
<developerConnection>
scm:git:ssh://git@github.com/spring-cloud/spring-cloud-commons.git
</developerConnection>
<tag>HEAD</tag>
</scm>
<properties>
<bintray.package>commons</bintray.package>
<maven-checkstyle-plugin.failsOnError>true</maven-checkstyle-plugin.failsOnError>
<maven-checkstyle-plugin.failsOnViolation>true
</maven-checkstyle-plugin.failsOnViolation>
</properties>
<build>
<plugins>
@@ -33,17 +41,39 @@
<additionalConfig>
<file>
<name>.settings/org.eclipse.jdt.ui.prefs</name>
<location>${maven.multiModuleProjectDirectory}/eclipse/org.eclipse.jdt.ui.prefs</location>
<location>
${maven.multiModuleProjectDirectory}/eclipse/org.eclipse.jdt.ui.prefs
</location>
</file>
<file>
<name>.settings/org.eclipse.jdt.core.prefs</name>
<location>${maven.multiModuleProjectDirectory}/eclipse/org.eclipse.jdt.core.prefs</location>
<location>
${maven.multiModuleProjectDirectory}/eclipse/org.eclipse.jdt.core.prefs
</location>
</file>
</additionalConfig>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
</plugins>
</reporting>
<profiles>
<profile>
<id>spring</id>

View File

@@ -1,12 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>spring-cloud-dependencies-parent</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>2.1.3.BUILD-SNAPSHOT</version>
<relativePath/>
<relativePath/>
</parent>
<artifactId>spring-cloud-commons-dependencies</artifactId>
<version>2.1.1.BUILD-SNAPSHOT</version>

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>

View File

@@ -57,10 +57,12 @@ public class CommonsClientAutoConfiguration {
@ConditionalOnBean(DiscoveryClient.class)
@ConditionalOnProperty(value = "spring.cloud.discovery.enabled", matchIfMissing = true)
protected static class DiscoveryLoadBalancerConfiguration {
@Bean
@ConditionalOnProperty(value = "spring.cloud.discovery.client.health-indicator.enabled", matchIfMissing = true)
public DiscoveryClientHealthIndicator discoveryClientHealthIndicator(
ObjectProvider<DiscoveryClient> discoveryClient, DiscoveryClientHealthIndicatorProperties properties) {
ObjectProvider<DiscoveryClient> discoveryClient,
DiscoveryClientHealthIndicatorProperties properties) {
return new DiscoveryClientHealthIndicator(discoveryClient, properties);
}
@@ -77,12 +79,14 @@ public class CommonsClientAutoConfiguration {
return HasFeatures.abstractFeatures(DiscoveryClient.class,
LoadBalancerClient.class);
}
}
@Configuration
@ConditionalOnClass(Endpoint.class)
@ConditionalOnProperty(value = "spring.cloud.features.enabled", matchIfMissing = true)
protected static class ActuatorConfiguration {
@Autowired(required = false)
private List<HasFeatures> hasFeatures = new ArrayList<>();
@@ -91,6 +95,7 @@ public class CommonsClientAutoConfiguration {
public FeaturesEndpoint featuresEndpoint() {
return new FeaturesEndpoint(this.hasFeatures);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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.
@@ -16,7 +16,6 @@
package org.springframework.cloud.client;
import java.net.URI;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -50,8 +49,8 @@ public class DefaultServiceInstance implements ServiceInstance {
* @param secure indicates whether or not the connection needs to be secure.
* @param metadata a map containing metadata.
*/
public DefaultServiceInstance(String instanceId, String serviceId, String host, int port, boolean secure,
Map<String, String> metadata) {
public DefaultServiceInstance(String instanceId, String serviceId, String host,
int port, boolean secure, Map<String, String> metadata) {
this.instanceId = instanceId;
this.serviceId = serviceId;
this.host = host;
@@ -67,7 +66,8 @@ public class DefaultServiceInstance implements ServiceInstance {
* @param port the port on which the service is running.
* @param secure indicates whether or not the connection needs to be secure.
*/
public DefaultServiceInstance(String instanceId, String serviceId, String host, int port, boolean secure) {
public DefaultServiceInstance(String instanceId, String serviceId, String host,
int port, boolean secure) {
this(instanceId, serviceId, host, port, secure, new LinkedHashMap<>());
}
@@ -77,7 +77,7 @@ public class DefaultServiceInstance implements ServiceInstance {
* @param port the port on which the service is running.
* @param secure indicates whether or not the connection needs to be secure.
* @param metadata a map containing metadata.
* @deprecated
* @deprecated - use other constructors
*/
@Deprecated
public DefaultServiceInstance(String serviceId, String host, int port, boolean secure,
@@ -90,7 +90,7 @@ public class DefaultServiceInstance implements ServiceInstance {
* @param host the host where the service instance can be found.
* @param port the port on which the service is running.
* @param secure indicates whether or not the connection needs to be secure.
* @deprecated
* @deprecated - use other constructors
*/
@Deprecated
public DefaultServiceInstance(String serviceId, String host, int port,
@@ -98,16 +98,6 @@ public class DefaultServiceInstance implements ServiceInstance {
this(serviceId, host, port, secure, new LinkedHashMap<>());
}
@Override
public URI getUri() {
return getUri(this);
}
@Override
public Map<String, String> getMetadata() {
return this.metadata;
}
/**
* Creates a URI from the given ServiceInstance's host:port.
* @param instance the ServiceInstance.
@@ -120,58 +110,69 @@ public class DefaultServiceInstance implements ServiceInstance {
return URI.create(uri);
}
@Override
public URI getUri() {
return getUri(this);
}
@Override
public Map<String, String> getMetadata() {
return this.metadata;
}
@Override
public String getInstanceId() {
return instanceId;
return this.instanceId;
}
@Override
public String getServiceId() {
return serviceId;
return this.serviceId;
}
@Override
public String getHost() {
return host;
return this.host;
}
@Override
public int getPort() {
return port;
return this.port;
}
@Override
public boolean isSecure() {
return secure;
return this.secure;
}
@Override
public String toString() {
return "DefaultServiceInstance{" +
"instanceId='" + instanceId + '\'' +
", serviceId='" + serviceId + '\'' +
", host='" + host + '\'' +
", port=" + port +
", secure=" + secure +
", metadata=" + metadata +
'}';
return "DefaultServiceInstance{" + "instanceId='" + this.instanceId + '\''
+ ", serviceId='" + this.serviceId + '\'' + ", host='" + this.host + '\''
+ ", port=" + this.port + ", secure=" + this.secure + ", metadata="
+ this.metadata + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DefaultServiceInstance that = (DefaultServiceInstance) o;
return port == that.port &&
secure == that.secure &&
Objects.equals(instanceId, that.instanceId) &&
Objects.equals(serviceId, that.serviceId) &&
Objects.equals(host, that.host) &&
Objects.equals(metadata, that.metadata);
return this.port == that.port && this.secure == that.secure
&& Objects.equals(this.instanceId, that.instanceId)
&& Objects.equals(this.serviceId, that.serviceId)
&& Objects.equals(this.host, that.host)
&& Objects.equals(this.metadata, that.metadata);
}
@Override
public int hashCode() {
return Objects.hash(instanceId, serviceId, host, port, secure, metadata);
return Objects.hash(this.instanceId, this.serviceId, this.host, this.port,
this.secure, this.metadata);
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.client;
import java.util.LinkedHashMap;
@@ -50,4 +66,5 @@ public class HostInfoEnvironmentPostProcessor
return utils.findFirstNonLoopbackHostInfo();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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.
@@ -21,6 +21,7 @@ import java.util.Map;
/**
* Represents an instance of a service in a discovery system.
*
* @author Spencer Gibb
* @author Tim Ysewyn
*/
@@ -69,4 +70,5 @@ public interface ServiceInstance {
default String getScheme() {
return null;
}
}

View File

@@ -1,11 +1,32 @@
/*
* Copyright 2012-2019 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.client;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import java.lang.annotation.*;
/**
* @author Spencer Gibb
*/
@@ -17,4 +38,5 @@ import java.lang.annotation.*;
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -26,15 +26,14 @@ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* @author Spencer Gibb
*/
@Endpoint(id = "features")
public class FeaturesEndpoint
implements ApplicationContextAware {
public class FeaturesEndpoint implements ApplicationContextAware {
private final List<HasFeatures> hasFeaturesList;
private ApplicationContext context;
public FeaturesEndpoint(List<HasFeatures> hasFeaturesList) {
@@ -90,26 +89,32 @@ public class FeaturesEndpoint
}
static class Features {
final List<Feature> enabled = new ArrayList<>();
final List<String> disabled = new ArrayList<>();
public List<Feature> getEnabled() {
return enabled;
return this.enabled;
}
public List<String> getDisabled() {
return disabled;
return this.disabled;
}
}
static class Feature {
final String type;
final String name;
final String version;
final String vendor;
public Feature(String name, String type, String version, String vendor) {
Feature(String name, String type, String version, String vendor) {
this.type = type;
this.name = name;
this.version = version;
@@ -117,51 +122,64 @@ public class FeaturesEndpoint
}
public String getType() {
return type;
return this.type;
}
public String getName() {
return name;
return this.name;
}
public String getVersion() {
return version;
return this.version;
}
public String getVendor() {
return vendor;
return this.vendor;
}
@Override
public String toString() {
return "Feature{" +
"type='" + type + '\'' +
", name='" + name + '\'' +
", version='" + version + '\'' +
", vendor='" + vendor + '\'' +
'}';
return "Feature{" + "type='" + this.type + '\'' + ", name='" + this.name
+ '\'' + ", version='" + this.version + '\'' + ", vendor='"
+ this.vendor + '\'' + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Feature feature = (Feature) o;
if (type != null ? !type.equals(feature.type) : feature.type != null) return false;
if (name != null ? !name.equals(feature.name) : feature.name != null) return false;
if (version != null ? !version.equals(feature.version) : feature.version != null) return false;
return vendor != null ? vendor.equals(feature.vendor) : feature.vendor == null;
if (this.type != null ? !this.type.equals(feature.type)
: feature.type != null) {
return false;
}
if (this.name != null ? !this.name.equals(feature.name)
: feature.name != null) {
return false;
}
if (this.version != null ? !this.version.equals(feature.version)
: feature.version != null) {
return false;
}
return this.vendor != null ? this.vendor.equals(feature.vendor)
: feature.vendor == null;
}
@Override
public int hashCode() {
int result = type != null ? type.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (version != null ? version.hashCode() : 0);
result = 31 * result + (vendor != null ? vendor.hashCode() : 0);
int result = this.type != null ? this.type.hashCode() : 0;
result = 31 * result + (this.name != null ? this.name.hashCode() : 0);
result = 31 * result + (this.version != null ? this.version.hashCode() : 0);
result = 31 * result + (this.vendor != null ? this.vendor.hashCode() : 0);
return result;
}
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.client.actuator;
import java.util.ArrayList;
@@ -14,13 +30,19 @@ public class HasFeatures {
private final List<NamedFeature> namedFeatures = new ArrayList<>();
public HasFeatures(List<Class<?>> abstractFeatures,
List<NamedFeature> namedFeatures) {
this.abstractFeatures.addAll(abstractFeatures);
this.namedFeatures.addAll(namedFeatures);
}
public static HasFeatures abstractFeatures(Class<?>... abstractFeatures) {
return new HasFeatures(Arrays.asList(abstractFeatures),
Collections.<NamedFeature> emptyList());
Collections.<NamedFeature>emptyList());
}
public static HasFeatures namedFeatures(NamedFeature... namedFeatures) {
return new HasFeatures(Collections.<Class<?>> emptyList(),
return new HasFeatures(Collections.<Class<?>>emptyList(),
Arrays.asList(namedFeatures));
}
@@ -34,12 +56,6 @@ public class HasFeatures {
new NamedFeature(name2, type2));
}
public HasFeatures(List<Class<?>> abstractFeatures,
List<NamedFeature> namedFeatures) {
this.abstractFeatures.addAll(abstractFeatures);
this.namedFeatures.addAll(namedFeatures);
}
public List<Class<?>> getAbstractFeatures() {
return this.abstractFeatures;
}
@@ -47,4 +63,5 @@ public class HasFeatures {
public List<NamedFeature> getNamedFeatures() {
return this.namedFeatures;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,14 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.actuator;
package org.springframework.cloud.client.actuator;
/**
* @author Spencer Gibb
*/
public class NamedFeature {
private final String name;
private final Class<?> type;
public NamedFeature(String name, Class<?> type) {
@@ -29,10 +31,11 @@ public class NamedFeature {
}
public String getName() {
return name;
return this.name;
}
public Class<?> getType() {
return type;
return this.type;
}
}

View File

@@ -22,16 +22,17 @@ import org.springframework.core.annotation.Order;
/**
* Imports a single circuit breaker implementation configuration.
*
* @author Spencer Gibb
*/
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableCircuitBreakerImportSelector extends
SpringFactoryImportSelector<EnableCircuitBreaker> {
public class EnableCircuitBreakerImportSelector
extends SpringFactoryImportSelector<EnableCircuitBreaker> {
@Override
protected boolean isEnabled() {
return getEnvironment().getProperty(
"spring.cloud.circuit.breaker.enabled", Boolean.class, Boolean.TRUE);
return getEnvironment().getProperty("spring.cloud.circuit.breaker.enabled",
Boolean.class, Boolean.TRUE);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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.
@@ -30,18 +30,19 @@ import org.springframework.core.Ordered;
*/
public interface DiscoveryClient extends Ordered {
/**
* Default order of the discovery client.
*/
int DEFAULT_ORDER = 0;
/**
* A human-readable description of the implementation, used in HealthIndicator.
*
* @return The description.
*/
String description();
/**
* Gets all ServiceInstances associated with a particular serviceId.
*
* @param serviceId The serviceId to query.
* @return A List of ServiceInstance.
*/
@@ -54,11 +55,11 @@ public interface DiscoveryClient extends Ordered {
/**
* Default implementation for getting order of discovery clients.
*
* @return order
*/
@Override
default int getOrder() {
return DEFAULT_ORDER;
}
}

View File

@@ -38,6 +38,8 @@ public @interface EnableDiscoveryClient {
/**
* If true, the ServiceRegistry will automatically register the local server.
* @return - {@code true} if you want to automatically register.
*/
boolean autoRegister() default true;
}

View File

@@ -16,6 +16,11 @@
package org.springframework.cloud.client.discovery;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import org.springframework.cloud.commons.util.SpringFactoryImportSelector;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
@@ -25,11 +30,6 @@ import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.type.AnnotationMetadata;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
/**
* @author Spencer Gibb
*/
@@ -48,12 +48,14 @@ public class EnableDiscoveryClientImportSelector
if (autoRegister) {
List<String> importsList = new ArrayList<>(Arrays.asList(imports));
importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
importsList.add(
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = importsList.toArray(new String[0]);
} else {
}
else {
Environment env = getEnvironment();
if(ConfigurableEnvironment.class.isInstance(env)) {
ConfigurableEnvironment configEnv = (ConfigurableEnvironment)env;
if (ConfigurableEnvironment.class.isInstance(env)) {
ConfigurableEnvironment configEnv = (ConfigurableEnvironment) env;
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("spring.cloud.service-registry.auto-registration.enabled", false);
MapPropertySource propertySource = new MapPropertySource(
@@ -68,8 +70,8 @@ public class EnableDiscoveryClientImportSelector
@Override
protected boolean isEnabled() {
return getEnvironment().getProperty(
"spring.cloud.discovery.enabled", Boolean.class, Boolean.TRUE);
return getEnvironment().getProperty("spring.cloud.discovery.enabled",
Boolean.class, Boolean.TRUE);
}
@Override

View File

@@ -23,23 +23,34 @@ import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.web.context.WebApplicationContext;
/**
* FIXME:
* Utility class for management server ports.
*
* @author Spencer Gibb
*/
public class ManagementServerPortUtils {
/** for testing */ static final boolean hasActuator;
public final class ManagementServerPortUtils {
// for testing
static final boolean hasActuator;
static {
boolean hasEndpointClass = hasClass("org.springframework.boot.actuate.endpoint.annotation.Endpoint");
boolean hasManagementServerPropertiesClass = hasClass("org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties");
boolean hasEndpointClass = hasClass(
"org.springframework.boot.actuate.endpoint.annotation.Endpoint");
boolean hasManagementServerPropertiesClass = hasClass(
"org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties");
hasActuator = hasEndpointClass && hasManagementServerPropertiesClass;
}
private ManagementServerPortUtils() {
throw new IllegalStateException("Can't instantiate a utility class");
}
private static boolean hasClass(String className) {
boolean hasClass;
try {
Class.forName(className);
hasClass = true;
} catch (ClassNotFoundException e) {
}
catch (ClassNotFoundException e) {
hasClass = false;
}
return hasClass;
@@ -76,9 +87,26 @@ public class ManagementServerPortUtils {
}
// TODO: copied from EndpointWebMvcAutoConfiguration.ManagementServerPort
public static enum ManagementServerPort {
DISABLE, SAME, DIFFERENT;
/**
* Enumeration for management server ports.
*/
public enum ManagementServerPort {
/**
* Disabled management server port.
*/
DISABLE,
/**
* Add it. TODO: Add it
*/
SAME,
/**
* Add it. TODO: Add it
*/
DIFFERENT;
public static ManagementServerPort get(BeanFactory beanFactory) {
if (!hasActuator) {
@@ -113,8 +141,9 @@ public class ManagementServerPortUtils {
return ((port == null)
|| (serverProperties.getPort() == null && port.equals(8080))
|| (port != 0 && port.equals(serverProperties.getPort())) ? SAME
: DIFFERENT);
: DIFFERENT);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -28,7 +28,7 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
/**
* A {@link DiscoveryClient} that is composed of other discovery clients and delegates
* calls to each of them in order.
*
*
* @author Biju Kunjummen
* @author Olga Maciaszek-Sharma
*/
@@ -49,7 +49,7 @@ public class CompositeDiscoveryClient implements DiscoveryClient {
@Override
public List<ServiceInstance> getInstances(String serviceId) {
if (this.discoveryClients != null) {
for (DiscoveryClient discoveryClient : discoveryClients) {
for (DiscoveryClient discoveryClient : this.discoveryClients) {
List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
if (instances != null && !instances.isEmpty()) {
return instances;
@@ -63,7 +63,7 @@ public class CompositeDiscoveryClient implements DiscoveryClient {
public List<String> getServices() {
LinkedHashSet<String> services = new LinkedHashSet<>();
if (this.discoveryClients != null) {
for (DiscoveryClient discoveryClient : discoveryClients) {
for (DiscoveryClient discoveryClient : this.discoveryClients) {
List<String> serviceForClient = discoveryClient.getServices();
if (serviceForClient != null) {
services.addAll(serviceForClient);
@@ -74,6 +74,7 @@ public class CompositeDiscoveryClient implements DiscoveryClient {
}
public List<DiscoveryClient> getDiscoveryClients() {
return discoveryClients;
return this.discoveryClients;
}
}

View File

@@ -1,5 +1,23 @@
/*
* Copyright 2012-2019 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.client.discovery.composite;
import java.util.List;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
@@ -7,22 +25,21 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import java.util.List;
/**
* Auto-configuration for composite discovery client.
*
*
* @author Biju Kunjummen
*/
@Configuration
@AutoConfigureBefore(SimpleDiscoveryClientAutoConfiguration.class)
public class CompositeDiscoveryClientAutoConfiguration {
@Bean
@Primary
public CompositeDiscoveryClient compositeDiscoveryClient(List<DiscoveryClient> discoveryClients) {
public CompositeDiscoveryClient compositeDiscoveryClient(
List<DiscoveryClient> discoveryClients) {
return new CompositeDiscoveryClient(discoveryClients);
}
}

View File

@@ -19,9 +19,9 @@ package org.springframework.cloud.client.discovery.event;
import org.springframework.context.ApplicationEvent;
/**
* An event that a DiscoveryClient implementation can broadcast if it supports
* heartbeats from the discovery server. Provides listeners with a basic indication
* of a state change in the service catalog.
* An event that a DiscoveryClient implementation can broadcast if it supports heartbeats
* from the discovery server. Provides listeners with a basic indication of a state change
* in the service catalog.
*
* @author Spencer Gibb
* @author Dave Syer
@@ -34,7 +34,6 @@ public class HeartbeatEvent extends ApplicationEvent {
/**
* Creates a new event with a source (for example, a discovery client) and a value.
* Neither parameter should be relied on to have specific content or format.
*
* @param source The source of the event.
* @param state The value indicating state of the catalog.
*/
@@ -46,10 +45,9 @@ public class HeartbeatEvent extends ApplicationEvent {
/**
* A value representing the state of the service catalog. The only requirement is that
* it changes when the catalog is updated; it can be as simple as a version counter or
* a hash. Implementations can provide information to help users visualize
* what is going on in the catalog, but users should not rely on the content (since
* the implementation of the underlying discovery might change).
*
* a hash. Implementations can provide information to help users visualize what is
* going on in the catalog, but users should not rely on the content (since the
* implementation of the underlying discovery might change).
* @return A value representing state of the service catalog.
*/
public Object getValue() {

View File

@@ -19,8 +19,8 @@ package org.springframework.cloud.client.discovery.event;
import java.util.concurrent.atomic.AtomicReference;
/**
* Helper class for listeners to the {@link HeartbeatEvent}, providing a convenient way
* to determine if there has been a change in state.
* Helper class for listeners to the {@link HeartbeatEvent}, providing a convenient way to
* determine if there has been a change in state.
*
* @author Dave Syer
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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.
@@ -21,6 +21,7 @@ import org.springframework.context.ApplicationEvent;
/**
* An event to fire before a service is registered.
*
* @author Ryan Baxter
*/
public class InstancePreRegisteredEvent extends ApplicationEvent {
@@ -29,8 +30,8 @@ public class InstancePreRegisteredEvent extends ApplicationEvent {
/**
* Create a new pre registration event.
*
* @param source the object on which the event initially occurred (never {@code null})
* @param registration the registration meta data
*/
public InstancePreRegisteredEvent(Object source, Registration registration) {
super(source);
@@ -42,6 +43,7 @@ public class InstancePreRegisteredEvent extends ApplicationEvent {
* @return the registration data
*/
public Registration getRegistration() {
return registration;
return this.registration;
}
}

View File

@@ -23,6 +23,7 @@ import org.springframework.context.ApplicationEvent;
* discovery service.
*
* @author Spencer Gibb
* @param <T> - type of configuration
*/
@SuppressWarnings("serial")
public class InstanceRegisteredEvent<T> extends ApplicationEvent {

View File

@@ -21,6 +21,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status;
@@ -29,23 +30,24 @@ import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
/**
* @author Spencer Gibb
*/
public class DiscoveryClientHealthIndicator implements DiscoveryHealthIndicator, Ordered,
ApplicationListener<InstanceRegisteredEvent<?>> {
private AtomicBoolean discoveryInitialized = new AtomicBoolean(false);
private int order = Ordered.HIGHEST_PRECEDENCE;
private final ObjectProvider<DiscoveryClient> discoveryClient;
private final DiscoveryClientHealthIndicatorProperties properties;
private final Log log = LogFactory.getLog(DiscoveryClientHealthIndicator.class);
public DiscoveryClientHealthIndicator(ObjectProvider<DiscoveryClient> discoveryClient, DiscoveryClientHealthIndicatorProperties properties) {
private AtomicBoolean discoveryInitialized = new AtomicBoolean(false);
private int order = Ordered.HIGHEST_PRECEDENCE;
public DiscoveryClientHealthIndicator(ObjectProvider<DiscoveryClient> discoveryClient,
DiscoveryClientHealthIndicatorProperties properties) {
this.discoveryClient = discoveryClient;
this.properties = properties;
}
@@ -53,7 +55,7 @@ public class DiscoveryClientHealthIndicator implements DiscoveryHealthIndicator,
@Override
public void onApplicationEvent(InstanceRegisteredEvent<?> event) {
if (this.discoveryInitialized.compareAndSet(false, true)) {
log.debug("Discovery Client has been initialized");
this.log.debug("Discovery Client has been initialized");
}
}
@@ -65,12 +67,13 @@ public class DiscoveryClientHealthIndicator implements DiscoveryHealthIndicator,
try {
DiscoveryClient client = this.discoveryClient.getIfAvailable();
List<String> services = client.getServices();
String description = (this.properties.isIncludeDescription()) ? client.description() : "";
builder.status(new Status("UP", description))
.withDetail("services", services);
String description = (this.properties.isIncludeDescription())
? client.description() : "";
builder.status(new Status("UP", description)).withDetail("services",
services);
}
catch (Exception e) {
log.error("Error", e);
this.log.error("Error", e);
builder.down(e);
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.client.discovery.health;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -13,7 +29,7 @@ public class DiscoveryClientHealthIndicatorProperties {
private boolean includeDescription = false;
public boolean isEnabled() {
return enabled;
return this.enabled;
}
public void setEnabled(boolean enabled) {
@@ -21,7 +37,7 @@ public class DiscoveryClientHealthIndicatorProperties {
}
public boolean isIncludeDescription() {
return includeDescription;
return this.includeDescription;
}
public void setIncludeDescription(boolean includeDescription) {
@@ -30,10 +46,12 @@ public class DiscoveryClientHealthIndicatorProperties {
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("DiscoveryClientHealthIndicatorProperties{");
sb.append("enabled=").append(enabled);
sb.append(", includeDescription=").append(includeDescription);
final StringBuffer sb = new StringBuffer(
"DiscoveryClientHealthIndicatorProperties{");
sb.append("enabled=").append(this.enabled);
sb.append(", includeDescription=").append(this.includeDescription);
sb.append('}');
return sb.toString();
}
}

View File

@@ -26,11 +26,12 @@ import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthIndicator;
/**
* Gathers all instances of DiscoveryHealthIndicator from a DiscoveryClient
* implementation and aggregates the statuses.
* Gathers all instances of DiscoveryHealthIndicator from a DiscoveryClient implementation
* and aggregates the statuses.
*
* @author Spencer Gibb
*/
//TODO: do we need this? Can they just be independent HealthIndicators?
// TODO: do we need this? Can they just be independent HealthIndicators?
public class DiscoveryCompositeHealthIndicator extends CompositeHealthIndicator {
private final ArrayList<Holder> healthIndicators = new ArrayList<>();
@@ -42,15 +43,19 @@ public class DiscoveryCompositeHealthIndicator extends CompositeHealthIndicator
for (DiscoveryHealthIndicator indicator : indicators) {
Holder holder = new Holder(indicator);
addHealthIndicator(indicator.getName(), holder);
healthIndicators.add(holder);
this.healthIndicators.add(holder);
}
}
public ArrayList<Holder> getHealthIndicators() {
return healthIndicators;
return this.healthIndicators;
}
/**
* Holder for the Health Indicator.
*/
public static class Holder implements HealthIndicator {
private DiscoveryHealthIndicator delegate;
public Holder(DiscoveryHealthIndicator delegate) {
@@ -63,8 +68,9 @@ public class DiscoveryCompositeHealthIndicator extends CompositeHealthIndicator
}
public DiscoveryHealthIndicator getDelegate() {
return delegate;
return this.delegate;
}
}
}

View File

@@ -20,6 +20,7 @@ import org.springframework.boot.actuate.health.Health;
/**
* A health indicator interface specific to a DiscoveryClient implementation.
*
* @author Spencer Gibb
*/
public interface DiscoveryHealthIndicator {

View File

@@ -25,8 +25,9 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
/**
* DiscoveryClient used when no implementations are found on the classpath.
*
* @deprecated Use {@link org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClient instead}.
*
* @deprecated Use
* {@link org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClient
* instead}.
* @author Dave Syer
*/

View File

@@ -23,6 +23,7 @@ import javax.annotation.PostConstruct;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -39,10 +40,9 @@ import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.env.Environment;
/**
*
* @deprecated Use
* {@link org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration instead}.
*
* {@link org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration
* instead}.
* @author Dave Syer
*/
@Configuration
@@ -52,6 +52,8 @@ import org.springframework.core.env.Environment;
public class NoopDiscoveryClientAutoConfiguration
implements ApplicationListener<ContextRefreshedEvent> {
private final Log log = LogFactory.getLog(NoopDiscoveryClientAutoConfiguration.class);
@Autowired(required = false)
private ServerProperties server;
@@ -66,8 +68,6 @@ public class NoopDiscoveryClientAutoConfiguration
private DefaultServiceInstance serviceInstance;
private final Log log = LogFactory.getLog(NoopDiscoveryClientAutoConfiguration.class);
@PostConstruct
public void init() {
String host = "localhost";
@@ -75,7 +75,7 @@ public class NoopDiscoveryClientAutoConfiguration
host = InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e) {
log.warn("Cannot get host info: (" + e.getMessage() + ")");
this.log.warn("Cannot get host info: (" + e.getMessage() + ")");
}
int port = findPort();
this.serviceInstance = new DefaultServiceInstance(
@@ -96,8 +96,8 @@ public class NoopDiscoveryClientAutoConfiguration
}
else {
// Apparently spring-web is not on the classpath
if (log.isDebugEnabled()) {
log.debug(
if (this.log.isDebugEnabled()) {
this.log.debug(
"Could not locate port in embedded container (spring-web not available)");
}
}
@@ -109,18 +109,21 @@ public class NoopDiscoveryClientAutoConfiguration
this.context.publishEvent(new InstanceRegisteredEvent<>(this, this.environment));
}
private interface PortFinder {
Integer findPort();
}
@Bean
public DiscoveryClient discoveryClient() {
return new NoopDiscoveryClient(this.serviceInstance);
}
private interface PortFinder {
Integer findPort();
}
@Configuration
@ConditionalOnClass(name = {"org.springframework.web.context.support.GenericWebApplicationContext",
"org.springframework.boot.context.embedded.EmbeddedWebApplicationContext"})
@ConditionalOnClass(name = {
"org.springframework.web.context.support.GenericWebApplicationContext",
"org.springframework.boot.context.embedded.EmbeddedWebApplicationContext" })
protected static class Boot15PortFinderConfiguration {
@Bean
@@ -129,16 +132,18 @@ public class NoopDiscoveryClientAutoConfiguration
@Override
public Integer findPort() {
// TODO: support reactive
/*if (context instanceof EmbeddedWebApplicationContext) {
EmbeddedServletContainer container = ((EmbeddedWebApplicationContext) context)
.getEmbeddedServletContainer();
if (container != null) {
return container.getPort();
}
}*/
/*
* if (context instanceof EmbeddedWebApplicationContext) {
* EmbeddedServletContainer container =
* ((EmbeddedWebApplicationContext) context)
* .getEmbeddedServletContainer(); if (container != null) { return
* container.getPort(); } }
*/
return null;
}
};
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -64,4 +64,5 @@ public class SimpleDiscoveryClient implements DiscoveryClient {
public int getOrder() {
return this.simpleDiscoveryProperties.getOrder();
}
}

View File

@@ -1,11 +1,27 @@
/*
* Copyright 2012-2019 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.client.discovery.simple;
import java.net.URI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.web.ServerProperties;
// import org.springframework.boot.context.embedded.EmbeddedServletContainer;
// import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.noop.NoopDiscoveryClientAutoConfiguration;
import org.springframework.cloud.commons.util.InetUtils;
@@ -14,9 +30,9 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.util.ClassUtils;
import java.net.URI;
// import org.springframework.boot.context.embedded.EmbeddedServletContainer;
// import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
/**
* Spring Boot auto-configuration for simple properties-based discovery client.
@@ -58,18 +74,15 @@ public class SimpleDiscoveryClientAutoConfiguration {
}
private int findPort() {
//FIXME: is what is the boot 2.0 equiv?
/*if (ClassUtils.isPresent(
"org.springframework.boot.context.embedded.EmbeddedWebApplicationContext",
null)) {
if (this.context instanceof EmbeddedWebApplicationContext) {
EmbeddedServletContainer container = ((EmbeddedWebApplicationContext) this.context)
.getEmbeddedServletContainer();
if (container != null) {
return container.getPort();
}
}
}*/
// FIXME: is what is the boot 2.0 equiv?
/*
* if (ClassUtils.isPresent(
* "org.springframework.boot.context.embedded.EmbeddedWebApplicationContext",
* null)) { if (this.context instanceof EmbeddedWebApplicationContext) {
* EmbeddedServletContainer container = ((EmbeddedWebApplicationContext)
* this.context) .getEmbeddedServletContainer(); if (container != null) { return
* container.getPort(); } } }
*/
if (this.server != null && this.server.getPort() != null
&& this.server.getPort() > 0) {
return this.server.getPort();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -31,10 +31,9 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
/**
* Properties to hold the details of a
* {@link org.springframework.cloud.client.discovery.DiscoveryClient} service instances
* for a given service.
* It also holds the user-configurable order that will be used to establish the
* precedence of this client in the list of clients
* used by {@link org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient}.
* for a given service. It also holds the user-configurable order that will be used to
* establish the precedence of this client in the list of clients used by
* {@link org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient}.
*
* @author Biju Kunjummen
* @author Olga Maciaszek-Sharma
@@ -43,6 +42,7 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
@ConfigurationProperties(prefix = "spring.cloud.discovery.client.simple")
public class SimpleDiscoveryProperties {
private Map<String, List<SimpleServiceInstance>> instances = new HashMap<>();
/**
@@ -83,25 +83,34 @@ public class SimpleDiscoveryProperties {
}
}
/**
* Basic implementation of {@link ServiceInstance}.
*/
public static class SimpleServiceInstance implements ServiceInstance {
/**
* The URI of the service instance. Will be parsed to extract the scheme, host,
* and port.
* and port.
*/
private URI uri;
private String host;
private int port;
private boolean secure;
/**
* Metadata for the service instance. Can be used by discovery clients to modify
* their behaviour per instance, e.g. when load balancing.
*/
private Map<String, String> metadata = new LinkedHashMap<>();
/**
* The unique identifier or name for the service instance.
*/
private String instanceId;
/**
* The identifier or name for the service. Multiple instances might share the same
* service ID.
@@ -115,16 +124,6 @@ public class SimpleDiscoveryProperties {
setUri(uri);
}
public void setUri(URI uri) {
this.uri = uri;
this.host = this.uri.getHost();
this.port = this.uri.getPort();
String scheme = this.uri.getScheme();
if ("https".equals(scheme)) {
this.secure = true;
}
}
@Override
public String getInstanceId() {
return this.instanceId;
@@ -163,9 +162,21 @@ public class SimpleDiscoveryProperties {
return this.uri;
}
public void setUri(URI uri) {
this.uri = uri;
this.host = this.uri.getHost();
this.port = this.uri.getPort();
String scheme = this.uri.getScheme();
if ("https".equals(scheme)) {
this.secure = true;
}
}
@Override
public Map<String, String> getMetadata() {
return this.metadata;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.hypermedia;
package org.springframework.cloud.client.hypermedia;
import java.util.Collections;
import java.util.List;
@@ -29,9 +29,10 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Registers a default {@link RemoteResourceRefresher} if at least one {@link RemoteResource} is declared in the system.
* Applies verification timings defined in the application properties.
*
* Registers a default {@link RemoteResourceRefresher} if at least one
* {@link RemoteResource} is declared in the system. Applies verification timings defined
* in the application properties.
*
* @author Oliver Gierke
*/
@Configuration
@@ -39,36 +40,47 @@ import org.springframework.context.annotation.Configuration;
@EnableConfigurationProperties(CloudHypermediaProperties.class)
public class CloudHypermediaAutoConfiguration {
@Autowired(required = false) List<RemoteResource> discoveredResources = Collections.emptyList();
@Autowired CloudHypermediaProperties properties;
@Autowired(required = false)
List<RemoteResource> discoveredResources = Collections.emptyList();
@Autowired
CloudHypermediaProperties properties;
@Bean
@ConditionalOnMissingBean
public RemoteResourceRefresher discoveredResourceRefresher() {
return new RemoteResourceRefresher(discoveredResources, properties.getRefresh().getFixedDelay(),
properties.getRefresh().getInitialDelay());
return new RemoteResourceRefresher(this.discoveredResources,
this.properties.getRefresh().getFixedDelay(),
this.properties.getRefresh().getInitialDelay());
}
/**
* Configuration for Cloud hypermedia.
*/
@ConfigurationProperties(prefix = "spring.cloud.hypermedia")
public static class CloudHypermediaProperties {
private Refresh refresh = new Refresh();
public Refresh getRefresh() {
return refresh;
return this.refresh;
}
public void setRefresh(Refresh refresh) {
this.refresh = refresh;
}
/**
* Configuration for Cloud hypermedia refresh.
*/
public static class Refresh {
private int fixedDelay = 5000;
private int initialDelay = 10000;
public int getFixedDelay() {
return fixedDelay;
return this.fixedDelay;
}
public void setFixedDelay(int fixedDelay) {
@@ -76,12 +88,15 @@ public class CloudHypermediaAutoConfiguration {
}
public int getInitialDelay() {
return initialDelay;
return this.initialDelay;
}
public void setInitialDelay(int initialDelay) {
this.initialDelay = initialDelay;
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.hypermedia;
import java.net.URI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
@@ -29,51 +31,55 @@ import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
/**
* A REST resource that is defined by a service reference and a traversal operation within that service.
* A REST resource that is defined by a service reference and a traversal operation within
* that service.
*
* @author Oliver Gierke
*/
public class DiscoveredResource implements RemoteResource {
private final ServiceInstanceProvider provider;
private final TraversalDefinition traversal;
private RestOperations restOperations = new RestTemplate();
private Link link = null;
private final TraversalDefinition traversal;
private final Logger log = LoggerFactory.getLogger(DiscoveredResource.class);
private RestOperations restOperations = new RestTemplate();
public DiscoveredResource(ServiceInstanceProvider provider, TraversalDefinition traversal) {
private Link link = null;
public DiscoveredResource(ServiceInstanceProvider provider,
TraversalDefinition traversal) {
this.provider = provider;
this.traversal = traversal;
}
/**
* Configures the {@link RestOperations} to use to execute the traversal and verifying HEAD calls.
*
* @param restOperations Can be {@literal null}; resorts to a default {@link RestTemplate} in that case.
*/
public void setRestOperations(RestOperations restOperations) {
this.restOperations = restOperations == null ? new RestTemplate() : restOperations;
}
public ServiceInstanceProvider getProvider() {
return provider;
return this.provider;
}
public TraversalDefinition getTraversal() {
return traversal;
return this.traversal;
}
public RestOperations getRestOperations() {
return restOperations;
return this.restOperations;
}
/**
* Configures the {@link RestOperations} to use to execute the traversal and verifying
* HEAD calls.
* @param restOperations Can be {@literal null}; resorts to a default
* {@link RestTemplate} in that case.
*/
public void setRestOperations(RestOperations restOperations) {
this.restOperations = restOperations == null ? new RestTemplate()
: restOperations;
}
@Override
public Link getLink() {
return link;
return this.link;
}
public void setLink(Link link) {
@@ -84,14 +90,13 @@ public class DiscoveredResource implements RemoteResource {
* Verifies the link to the current.
*/
public void verifyOrDiscover() {
this.link = link == null ? discoverLink() : verify(link);
this.link = this.link == null ? discoverLink() : verify(this.link);
}
/**
* Verifies the given {@link Link} by issuing an HTTP HEAD request to the resource.
*
* @param link Must not be {@literal null}.
* @return
* @return - link to the resource
*/
private Link verify(Link link) {
@@ -101,15 +106,16 @@ public class DiscoveredResource implements RemoteResource {
String uri = link.expand().getHref();
log.debug("Verifying link pointing to {}…", uri);
restOperations.headForHeaders(uri);
log.debug("Successfully verified link!");
this.log.debug("Verifying link pointing to {}…", uri);
this.restOperations.headForHeaders(uri);
this.log.debug("Successfully verified link!");
return link;
} catch (RestClientException o_O) {
}
catch (RestClientException o_O) {
log.debug("Verification failed, marking as outdated!");
this.log.debug("Verification failed, marking as outdated!");
return null;
}
}
@@ -118,7 +124,7 @@ public class DiscoveredResource implements RemoteResource {
try {
ServiceInstance service = provider.getServiceInstance();
ServiceInstance service = this.provider.getServiceInstance();
if (service == null) {
return null;
@@ -127,21 +133,24 @@ public class DiscoveredResource implements RemoteResource {
URI uri = service.getUri();
String serviceId = service.getServiceId();
log.debug("Discovered {} system at {}. Discovering resource…", serviceId, uri);
this.log.debug("Discovered {} system at {}. Discovering resource…", serviceId,
uri);
Traverson traverson = new Traverson(uri, MediaTypes.HAL_JSON);
Link link = traversal.buildTraversal(traverson).asTemplatedLink();
Link link = this.traversal.buildTraversal(traverson).asTemplatedLink();
log.debug("Found link pointing to {}.", link.getHref());
this.log.debug("Found link pointing to {}.", link.getHref());
return link;
} catch (RuntimeException o_O) {
}
catch (RuntimeException o_O) {
this.link = null;
log.debug("Target system unavailable. Got: ", o_O.getMessage());
this.log.debug("Target system unavailable. Got: ", o_O.getMessage());
return null;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.hypermedia;
import java.util.List;
@@ -21,14 +22,16 @@ import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
/**
* {@link ServiceInstanceProvider} to work with a {@link DiscoveryClient} to look up a service by name. Picks the
* first one returned by the configured {@link DiscoveryClient}.
*
* {@link ServiceInstanceProvider} to work with a {@link DiscoveryClient} to look up a
* service by name. Picks the first one returned by the configured
* {@link DiscoveryClient}.
*
* @author Oliver Gierke
*/
public class DynamicServiceInstanceProvider implements ServiceInstanceProvider {
private final DiscoveryClient client;
private final String serviceName;
public DynamicServiceInstanceProvider(DiscoveryClient client, String serviceName) {
@@ -36,20 +39,23 @@ public class DynamicServiceInstanceProvider implements ServiceInstanceProvider {
this.serviceName = serviceName;
}
/*
* (non-Javadoc)
* @see example.customers.integration.ServiceInstanceProvider#getServiceInstance()
*/
/*
* (non-Javadoc)
*
* @see example.customers.integration.ServiceInstanceProvider#getServiceInstance()
*/
@Override
public ServiceInstance getServiceInstance() {
try {
List<ServiceInstance> instances = client.getInstances(serviceName);
List<ServiceInstance> instances = this.client.getInstances(this.serviceName);
return instances.isEmpty() ? null : instances.get(0);
} catch (RuntimeException o_O) {
}
catch (RuntimeException o_O) {
return null;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.hypermedia;
import org.springframework.hateoas.Link;
@@ -25,15 +26,17 @@ import org.springframework.hateoas.Link;
public interface RemoteResource {
/**
* Returns the {@link Link} to the resource if it is available, or {@literal null}
* if it is gone (i.e. it either is generally unavailable or can't be discovered).
* Returns the {@link Link} to the resource if it is available, or {@literal null} if
* it is gone (i.e. it either is generally unavailable or can't be discovered).
* @return a link to the resource.
*/
Link getLink();
/**
* Discovers the resource if it hasn't been discovered yet or has become
* unavailable. If a link has been discovered previously, it is verified and either
* confirmed or removed to indicate that it's not available anymore.
* Discovers the resource if it hasn't been discovered yet or has become unavailable.
* If a link has been discovered previously, it is verified and either confirmed or
* removed to indicate that it's not available anymore.
*/
void verifyOrDiscover();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.hypermedia;
import java.util.List;
@@ -22,39 +23,46 @@ import org.springframework.scheduling.config.IntervalTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
/**
* A {@link ScheduledTaskRegistrar} that verifies all {@link DiscoveredResource} instances in the system, based
* on the given timing configuration.
*
* A {@link ScheduledTaskRegistrar} that verifies all {@link DiscoveredResource} instances
* in the system, based on the given timing configuration.
*
* @author Oliver Gierke
*/
public class RemoteResourceRefresher extends ContextLifecycleScheduledTaskRegistrar {
private final List<RemoteResource> discoveredResources;
private final int fixedDelay, initialDelay;
public RemoteResourceRefresher(List<RemoteResource> discoveredResources, int fixedDelay, int initialDelay) {
private final int fixedDelay;
private final int initialDelay;
public RemoteResourceRefresher(List<RemoteResource> discoveredResources,
int fixedDelay, int initialDelay) {
this.discoveredResources = discoveredResources;
this.fixedDelay = fixedDelay;
this.initialDelay = initialDelay;
}
/*
* (non-Javadoc)
* @see org.springframework.scheduling.config.ContextLifecycleScheduledTaskRegistrar#afterPropertiesSet()
*/
/*
* (non-Javadoc)
*
* @see org.springframework.scheduling.config.ContextLifecycleScheduledTaskRegistrar#
* afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() {
for (final RemoteResource resource : discoveredResources) {
for (final RemoteResource resource : this.discoveredResources) {
addFixedDelayTask(new IntervalTask(new Runnable() {
@Override
public void run() {
resource.verifyOrDiscover();
}
}, fixedDelay, initialDelay));
}, this.fixedDelay, this.initialDelay));
}
super.afterPropertiesSet();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,22 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.hypermedia;
import org.springframework.cloud.client.ServiceInstance;
/**
* A component that will provide a {@link ServiceInstance}, or can express the absence of one by
* returning {@literal null}.
*
* A component that will provide a {@link ServiceInstance}, or can express the absence of
* one by returning {@literal null}.
*
* @author Oliver Gierke
*/
public interface ServiceInstanceProvider {
/**
* Returns the service instance or {@literal null} if the service is currently unavailable.
*
* @return The service instance, or {@literal null} if the service is currently unavailable.
* Returns the service instance or {@literal null} if the service is currently
* unavailable.
* @return The service instance, or {@literal null} if the service is currently
* unavailable.
*/
ServiceInstance getServiceInstance();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.hypermedia;
import org.springframework.cloud.client.ServiceInstance;
/**
* A {@link ServiceInstanceProvider} that will always return the configured {@link ServiceInstance}.
*
* A {@link ServiceInstanceProvider} that will always return the configured
* {@link ServiceInstance}.
*
* @author Oliver Gierke
*/
public class StaticServiceInstanceProvider implements ServiceInstanceProvider {
@@ -30,12 +32,14 @@ public class StaticServiceInstanceProvider implements ServiceInstanceProvider {
this.instance = instance;
}
/*
* (non-Javadoc)
* @see example.customers.integration.ServiceInstanceProvider#getServiceInstance()
*/
/*
* (non-Javadoc)
*
* @see example.customers.integration.ServiceInstanceProvider#getServiceInstance()
*/
@Override
public ServiceInstance getServiceInstance() {
return instance;
return this.instance;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.hypermedia;
import org.springframework.hateoas.client.Traverson;
@@ -27,6 +28,8 @@ public interface TraversalDefinition {
/**
* @param traverson The Traverson instance to run the traversal on.
* @return the builder for traversing
*/
TraversalBuilder buildTraversal(Traverson traverson);
}

View File

@@ -39,9 +39,9 @@ import org.springframework.web.client.AsyncRestTemplate;
@ConditionalOnClass(AsyncRestTemplate.class)
public class AsyncLoadBalancerAutoConfiguration {
@Configuration
static class AsyncRestTemplateCustomizerConfig {
@LoadBalanced
@Autowired(required = false)
private List<AsyncRestTemplate> restTemplates = Collections.emptyList();
@@ -60,12 +60,15 @@ public class AsyncLoadBalancerAutoConfiguration {
}
};
}
}
@Configuration
static class LoadBalancerInterceptorConfig {
@Bean
public AsyncLoadBalancerInterceptor asyncLoadBalancerInterceptor(LoadBalancerClient loadBalancerClient) {
public AsyncLoadBalancerInterceptor asyncLoadBalancerInterceptor(
LoadBalancerClient loadBalancerClient) {
return new AsyncLoadBalancerInterceptor(loadBalancerClient);
}
@@ -82,5 +85,7 @@ public class AsyncLoadBalancerAutoConfiguration {
}
};
}
}
}

View File

@@ -16,6 +16,9 @@
package org.springframework.cloud.client.loadbalancer;
import java.io.IOException;
import java.net.URI;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.AsyncClientHttpRequestExecution;
@@ -23,9 +26,6 @@ import org.springframework.http.client.AsyncClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.concurrent.ListenableFuture;
import java.io.IOException;
import java.net.URI;
/**
* @author Rob Worsnop
*/
@@ -38,21 +38,22 @@ public class AsyncLoadBalancerInterceptor implements AsyncClientHttpRequestInter
}
@Override
public ListenableFuture<ClientHttpResponse> intercept(final HttpRequest request, final byte[] body,
final AsyncClientHttpRequestExecution execution) throws IOException {
public ListenableFuture<ClientHttpResponse> intercept(final HttpRequest request,
final byte[] body, final AsyncClientHttpRequestExecution execution)
throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
return this.loadBalancer.execute(serviceName,
new LoadBalancerRequest<ListenableFuture<ClientHttpResponse>>() {
@Override
public ListenableFuture<ClientHttpResponse> apply(final ServiceInstance instance)
throws Exception {
public ListenableFuture<ClientHttpResponse> apply(
final ServiceInstance instance) throws Exception {
HttpRequest serviceRequest = new ServiceRequestWrapper(request,
instance, loadBalancer);
instance, AsyncLoadBalancerInterceptor.this.loadBalancer);
return execution.executeAsync(serviceRequest, body);
}
});
}
}
}

View File

@@ -22,6 +22,7 @@ import org.springframework.web.client.AsyncRestTemplate;
* @author Rob Worsnop
*/
public interface AsyncRestTemplateCustomizer {
void customize(AsyncRestTemplate restTemplate);
}
void customize(AsyncRestTemplate restTemplate);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,72 +13,81 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.loadbalancer;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.AbstractClientHttpResponse;
import org.springframework.http.client.ClientHttpResponse;
/**
* {@link RetryableStatusCodeException} that captures a {@link ClientHttpResponse}.
*
* @author Ryan Baxter
*/
public class ClientHttpResponseStatusCodeException extends RetryableStatusCodeException {
private ClientHttpResponseWrapper response;
private final ClientHttpResponseWrapper response;
/**
* Constructor.
* @param serviceId The service ID.
* @param response The response object.
* @throws IOException Thrown if the {@link ClientHttpResponse} response code cannot be retrieved.
* @param body The response body.
* @throws IOException Thrown if the {@link ClientHttpResponse} response code cannot
* be retrieved.
*/
public ClientHttpResponseStatusCodeException(String serviceId, ClientHttpResponse response, byte[] body) throws IOException {
public ClientHttpResponseStatusCodeException(String serviceId,
ClientHttpResponse response, byte[] body) throws IOException {
super(serviceId, response.getRawStatusCode(), response, null);
this.response = new ClientHttpResponseWrapper(response, body);
}
@Override
public ClientHttpResponse getResponse() {
return response;
return this.response;
}
static class ClientHttpResponseWrapper extends AbstractClientHttpResponse {
private ClientHttpResponse response;
private byte[] body;
public ClientHttpResponseWrapper(ClientHttpResponse response, byte[] body) {
ClientHttpResponseWrapper(ClientHttpResponse response, byte[] body) {
this.response = response;
this.body = body;
}
@Override
public int getRawStatusCode() throws IOException {
return response.getRawStatusCode();
return this.response.getRawStatusCode();
}
@Override
public String getStatusText() throws IOException {
return response.getStatusText();
return this.response.getStatusText();
}
@Override
public void close() {
response.close();
this.response.close();
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream(body);
return new ByteArrayInputStream(this.body);
}
@Override
public HttpHeaders getHeaders() {
return response.getHeaders();
return this.response.getHeaders();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.loadbalancer;
import org.springframework.http.HttpRequest;
@@ -20,83 +21,99 @@ import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryPolicy;
/**
* {@link RetryPolicy} used by the {@link LoadBalancerClient} when retrying failed requests.
* {@link RetryPolicy} used by the {@link LoadBalancerClient} when retrying failed
* requests.
*
* @author Ryan Baxter
*/
public class InterceptorRetryPolicy implements RetryPolicy {
private HttpRequest request;
private LoadBalancedRetryPolicy policy;
private ServiceInstanceChooser serviceInstanceChooser;
private String serviceName;
private HttpRequest request;
/**
* Creates a new retry policy.
* @param request The request that will be retried.
* @param policy The retry policy from the load balancer.
* @param serviceInstanceChooser The load balancer client.
* @param serviceName The name of the service.
*/
public InterceptorRetryPolicy(HttpRequest request, LoadBalancedRetryPolicy policy,
ServiceInstanceChooser serviceInstanceChooser, String serviceName) {
this.request = request;
this.policy = policy;
this.serviceInstanceChooser = serviceInstanceChooser;
this.serviceName = serviceName;
}
private LoadBalancedRetryPolicy policy;
@Override
public boolean canRetry(RetryContext context) {
LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext)context;
if(lbContext.getRetryCount() == 0 && lbContext.getServiceInstance() == null) {
//We haven't even tried to make the request yet so return true so we do
lbContext.setServiceInstance(serviceInstanceChooser.choose(serviceName));
return true;
}
return policy.canRetryNextServer(lbContext);
}
private ServiceInstanceChooser serviceInstanceChooser;
@Override
public RetryContext open(RetryContext parent) {
return new LoadBalancedRetryContext(parent, request);
}
private String serviceName;
/**
* Creates a new retry policy.
* @param request The request that will be retried.
* @param policy The retry policy from the load balancer.
* @param serviceInstanceChooser The load balancer client.
* @param serviceName The name of the service.
*/
public InterceptorRetryPolicy(HttpRequest request, LoadBalancedRetryPolicy policy,
ServiceInstanceChooser serviceInstanceChooser, String serviceName) {
this.request = request;
this.policy = policy;
this.serviceInstanceChooser = serviceInstanceChooser;
this.serviceName = serviceName;
}
@Override
public void close(RetryContext context) {
policy.close((LoadBalancedRetryContext)context);
}
@Override
public boolean canRetry(RetryContext context) {
LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;
if (lbContext.getRetryCount() == 0 && lbContext.getServiceInstance() == null) {
// We haven't even tried to make the request yet so return true so we do
lbContext.setServiceInstance(
this.serviceInstanceChooser.choose(this.serviceName));
return true;
}
return this.policy.canRetryNextServer(lbContext);
}
@Override
public RetryContext open(RetryContext parent) {
return new LoadBalancedRetryContext(parent, this.request);
}
@Override
public void registerThrowable(RetryContext context, Throwable throwable) {
LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;
//this is important as it registers the last exception in the context and also increases the retry count
lbContext.registerThrowable(throwable);
//let the policy know about the exception as well
policy.registerThrowable(lbContext, throwable);
}
@Override
public void close(RetryContext context) {
this.policy.close((LoadBalancedRetryContext) context);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@Override
public void registerThrowable(RetryContext context, Throwable throwable) {
LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;
// this is important as it registers the last exception in the context and also
// increases the retry count
lbContext.registerThrowable(throwable);
// let the policy know about the exception as well
this.policy.registerThrowable(lbContext, throwable);
}
InterceptorRetryPolicy that = (InterceptorRetryPolicy) o;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!request.equals(that.request)) return false;
if (!policy.equals(that.policy)) return false;
if (!serviceInstanceChooser.equals(that.serviceInstanceChooser)) return false;
return serviceName.equals(that.serviceName);
InterceptorRetryPolicy that = (InterceptorRetryPolicy) o;
}
if (!this.request.equals(that.request)) {
return false;
}
if (!this.policy.equals(that.policy)) {
return false;
}
if (!this.serviceInstanceChooser.equals(that.serviceInstanceChooser)) {
return false;
}
return this.serviceName.equals(that.serviceName);
}
@Override
public int hashCode() {
int result = this.request.hashCode();
result = 31 * result + this.policy.hashCode();
result = 31 * result + this.serviceInstanceChooser.hashCode();
result = 31 * result + this.serviceName.hashCode();
return result;
}
@Override
public int hashCode() {
int result = request.hashCode();
result = 31 * result + policy.hashCode();
result = 31 * result + serviceInstanceChooser.hashCode();
result = 31 * result + serviceName.hashCode();
return result;
}
}

View File

@@ -16,8 +16,6 @@
package org.springframework.cloud.client.loadbalancer;
import org.springframework.beans.factory.annotation.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
@@ -25,6 +23,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient.
* @author Spencer Gibb
@@ -35,4 +35,5 @@ import java.lang.annotation.Target;
@Inherited
@Qualifier
public @interface LoadBalanced {
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,18 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.loadbalancer;
import java.net.URI;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryException;
import java.net.URI;
/**
* An implementation of {@link RecoveryCallback} which relies on an implementation
* of {@link RetryableStatusCodeException} to contain the last response object from
* the request.
* An implementation of {@link RecoveryCallback} which relies on an implementation of
* {@link RetryableStatusCodeException} to contain the last response object from the
* request.
*
* @param <T> - response type to return
* @param <R> - response type from the HTTP client
* @author LiYuan Lee
*/
public abstract class LoadBalancedRecoveryCallback<T, R> implements RecoveryCallback<T> {
@@ -44,10 +48,12 @@ public abstract class LoadBalancedRecoveryCallback<T, R> implements RecoveryCall
if (lastThrowable instanceof RetryableStatusCodeException) {
RetryableStatusCodeException ex = (RetryableStatusCodeException) lastThrowable;
return createResponse((R) ex.getResponse(), ex.getUri());
} else if (lastThrowable instanceof Exception){
throw (Exception)lastThrowable;
}
else if (lastThrowable instanceof Exception) {
throw (Exception) lastThrowable;
}
}
throw new RetryException("Could not recover", lastThrowable);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.loadbalancer;
import org.springframework.cloud.client.ServiceInstance;
@@ -22,52 +23,55 @@ import org.springframework.retry.context.RetryContextSupport;
/**
* {@link RetryContext} for load-balanced retries.
*
* @author Ryan Baxter
*/
public class LoadBalancedRetryContext extends RetryContextSupport {
private HttpRequest request;
private ServiceInstance serviceInstance;
private HttpRequest request;
/**
* Creates a new load-balanced context.
* @param parent The parent context.
* @param request The request that is being load-balanced.
*/
public LoadBalancedRetryContext(RetryContext parent, HttpRequest request) {
super(parent);
this.request = request;
}
private ServiceInstance serviceInstance;
/**
* Gets the request that is being load-balanced.
* @return The request that is being load-balanced.
*/
public HttpRequest getRequest() {
return request;
}
/**
* Creates a new load-balanced context.
* @param parent The parent context.
* @param request The request that is being load-balanced.
*/
public LoadBalancedRetryContext(RetryContext parent, HttpRequest request) {
super(parent);
this.request = request;
}
/**
* Sets the request that is being load-balanced.
* @param request The request to be load balanced.
*/
public void setRequest(HttpRequest request) {
this.request = request;
}
/**
* Gets the request that is being load-balanced.
* @return The request that is being load-balanced.
*/
public HttpRequest getRequest() {
return this.request;
}
/**
* Gets the service instance used during the retry.
* @return The service instance used during the retry.
*/
public ServiceInstance getServiceInstance() {
return serviceInstance;
}
/**
* Sets the request that is being load-balanced.
* @param request The request to be load balanced.
*/
public void setRequest(HttpRequest request) {
this.request = request;
}
/**
* Gets the service instance used during the retry.
* @return The service instance used during the retry.
*/
public ServiceInstance getServiceInstance() {
return this.serviceInstance;
}
/**
* Sets the service instance to use during the retry.
* @param serviceInstance The service instance to use during the retry.
*/
public void setServiceInstance(ServiceInstance serviceInstance) {
this.serviceInstance = serviceInstance;
}
/**
* Sets the service instance to use during the retry.
* @param serviceInstance The service instance to use during the retry.
*/
public void setServiceInstance(ServiceInstance serviceInstance) {
this.serviceInstance = serviceInstance;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.loadbalancer;
import org.springframework.retry.RetryListener;
@@ -21,6 +22,7 @@ import org.springframework.retry.backoff.NoBackOffPolicy;
/**
* Factory class used to customize the retry functionality throughout Spring Cloud.
*
* @author Ryan Baxter
*/
public interface LoadBalancedRetryFactory {
@@ -31,7 +33,8 @@ public interface LoadBalancedRetryFactory {
* @param serviceInstanceChooser Used to get the next server from a load balancer.
* @return A retry policy for the service.
*/
default LoadBalancedRetryPolicy createRetryPolicy(String service, ServiceInstanceChooser serviceInstanceChooser) {
default LoadBalancedRetryPolicy createRetryPolicy(String service,
ServiceInstanceChooser serviceInstanceChooser) {
return null;
}
@@ -52,4 +55,5 @@ public interface LoadBalancedRetryFactory {
default BackOffPolicy createBackOffPolicy(String service) {
return new NoBackOffPolicy();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,51 +13,56 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.loadbalancer;
/**
* Retry logic to use for the {@link LoadBalancerClient}.
*
* @author Ryan Baxter
*/
public interface LoadBalancedRetryPolicy {
/**
* Return true to retry the failed request on the same server.
* This method may be called more than once when executing a single operation.
* @param context The context for the retry operation.
* @return True to retry the failed request on the same server; false otherwise.
*/
public boolean canRetrySameServer(LoadBalancedRetryContext context);
/**
* Return true to retry the failed request on the same server. This method may be
* called more than once when executing a single operation.
* @param context The context for the retry operation.
* @return True to retry the failed request on the same server; false otherwise.
*/
boolean canRetrySameServer(LoadBalancedRetryContext context);
/**
* Return true to retry the failed request on the next server from the load balancer.
* This method may be called more than once when executing a single operation.
* @param context The context for the retry operation.
* @return True to retry the failed request on the next server from the load balancer; false otherwise.
*/
public boolean canRetryNextServer(LoadBalancedRetryContext context);
/**
* Return true to retry the failed request on the next server from the load balancer.
* This method may be called more than once when executing a single operation.
* @param context The context for the retry operation.
* @return True to retry the failed request on the next server from the load balancer;
* false otherwise.
*/
boolean canRetryNextServer(LoadBalancedRetryContext context);
/**
* Called when the retry operation has ended.
* @param context The context for the retry operation.
*/
public abstract void close(LoadBalancedRetryContext context);
/**
* Called when the retry operation has ended.
* @param context The context for the retry operation.
*/
void close(LoadBalancedRetryContext context);
/**
* Called when the execution fails.
* @param context The context for the retry operation.
* @param throwable The throwable from the failed execution.
*/
public abstract void registerThrowable(LoadBalancedRetryContext context, Throwable throwable);
/**
* Called when the execution fails.
* @param context The context for the retry operation.
* @param throwable The throwable from the failed execution.
*/
void registerThrowable(LoadBalancedRetryContext context, Throwable throwable);
/**
* If an exception is not thrown when making a request, this method will be called to
* see if the client would like to retry the request based on the status code
* returned. For example, in Cloud Foundry, the router will return a <code>404</code>
* when an app is not available. Since HTTP clients do not throw an exception when a
* <code>404</code> is returned, <code>retryableStatusCode</code> allows clients to
* force a retry.
* @param statusCode The HTTP status code.
* @return True if a retry should be attempted; false to just return the response.
*/
boolean retryableStatusCode(int statusCode);
/**
* If an exception is not thrown when making a request, this method will be called to see if the
* client would like to retry the request based on the status code returned. For example, in
* Cloud Foundry, the router will return a <code>404</code> when an app is not available. Since
* HTTP clients do not throw an exception when a <code>404</code> is returned,
* <code>retryableStatusCode</code> allows clients to force a retry.
* @param statusCode The HTTP status code.
* @return True if a retry should be attempted; false to just return the response.
*/
public boolean retryableStatusCode(int statusCode);
}

View File

@@ -16,6 +16,10 @@
package org.springframework.cloud.client.loadbalancer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
@@ -27,14 +31,9 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.retry.backoff.BackOffPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Auto-configuration for Ribbon (client-side load balancing).
*
@@ -53,31 +52,32 @@ public class LoadBalancerAutoConfiguration {
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
@@ -90,14 +90,18 @@ public class LoadBalancerAutoConfiguration {
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
/**
* Auto configuration for retry mechanism.
*/
@Configuration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryAutoConfiguration {
@@ -105,17 +109,24 @@ public class LoadBalancerAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryFactory() {
return new LoadBalancedRetryFactory() {};
return new LoadBalancedRetryFactory() {
};
}
}
/**
* Auto configuration for retry intercepting mechanism.
*/
@Configuration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryInterceptorAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RetryLoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties,
LoadBalancerClient loadBalancerClient,
LoadBalancerRetryProperties properties,
LoadBalancerRequestFactory requestFactory,
LoadBalancedRetryFactory loadBalancedRetryFactory) {
return new RetryLoadBalancerInterceptor(loadBalancerClient, properties,
@@ -127,11 +138,13 @@ public class LoadBalancerAutoConfiguration {
public RestTemplateCustomizer restTemplateCustomizer(
final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
}

View File

@@ -16,13 +16,14 @@
package org.springframework.cloud.client.loadbalancer;
import org.springframework.cloud.client.ServiceInstance;
import java.io.IOException;
import java.net.URI;
import org.springframework.cloud.client.ServiceInstance;
/**
* Represents a client-side load balancer.
*
* @author Spencer Gibb
*/
public interface LoadBalancerClient extends ServiceInstanceChooser {
@@ -33,6 +34,8 @@ public interface LoadBalancerClient extends ServiceInstanceChooser {
* @param serviceId The service ID to look up the LoadBalancer.
* @param request Allows implementations to execute pre and post actions, such as
* incrementing metrics.
* @param <T> type of the response
* @throws IOException in case of IO issues.
* @return The result of the LoadBalancerRequest callback on the selected
* ServiceInstance.
*/
@@ -45,19 +48,23 @@ public interface LoadBalancerClient extends ServiceInstanceChooser {
* @param serviceInstance The service to execute the request to.
* @param request Allows implementations to execute pre and post actions, such as
* incrementing metrics.
* @param <T> type of the response
* @throws IOException in case of IO issues.
* @return The result of the LoadBalancerRequest callback on the selected
* ServiceInstance.
*/
<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;
<T> T execute(String serviceId, ServiceInstance serviceInstance,
LoadBalancerRequest<T> request) throws IOException;
/**
* Creates a proper URI with a real host and port for systems to utilize.
* Some systems use a URI with the logical service name as the host,
* such as http://myservice/path/to/service. This will replace the
* service name with the host:port from the ServiceInstance.
* @param instance
* Creates a proper URI with a real host and port for systems to utilize. Some systems
* use a URI with the logical service name as the host, such as
* http://myservice/path/to/service. This will replace the service name with the
* host:port from the ServiceInstance.
* @param instance service instance to reconstruct the URI
* @param original A URI with the host as a logical service name.
* @return A reconstructed URI.
*/
URI reconstructURI(ServiceInstance instance, URI original);
}

View File

@@ -34,9 +34,11 @@ import org.springframework.util.Assert;
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
}
@@ -51,7 +53,10 @@ public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
Assert.state(serviceName != null,
"Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(serviceName,
this.requestFactory.createRequest(request, body, execution));
}
}

View File

@@ -19,12 +19,14 @@ package org.springframework.cloud.client.loadbalancer;
import org.springframework.cloud.client.ServiceInstance;
/**
* Simple interface used by LoadBalancerClient to apply metrics or pre and post
* actions around load balancer requests.
* Simple interface used by LoadBalancerClient to apply metrics or pre and post actions
* around load balancer requests.
*
* @param <T> type of the response
* @author Spencer Gibb
*/
public interface LoadBalancerRequest<T> {
public T apply(ServiceInstance instance) throws Exception;
T apply(ServiceInstance instance) throws Exception;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -18,23 +18,22 @@ package org.springframework.cloud.client.loadbalancer;
import java.util.List;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
/**
* Creates {@link LoadBalancerRequest}s for {@link LoadBalancerInterceptor} and
* {@link RetryLoadBalancerInterceptor}. Applies
* {@link LoadBalancerRequestTransformer}s to the intercepted
* {@link HttpRequest}.
*
* {@link RetryLoadBalancerInterceptor}. Applies {@link LoadBalancerRequestTransformer}s
* to the intercepted {@link HttpRequest}.
*
* @author William Tran
*
*/
public class LoadBalancerRequestFactory {
private LoadBalancerClient loadBalancer;
private List<LoadBalancerRequestTransformer> transformers;
public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer,
@@ -47,17 +46,20 @@ public class LoadBalancerRequestFactory {
this.loadBalancer = loadBalancer;
}
public LoadBalancerRequest<ClientHttpResponse> createRequest(final HttpRequest request,
final byte[] body, final ClientHttpRequestExecution execution) {
public LoadBalancerRequest<ClientHttpResponse> createRequest(
final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) {
return instance -> {
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, loadBalancer);
if (transformers != null) {
for (LoadBalancerRequestTransformer transformer : transformers) {
serviceRequest = transformer.transformRequest(serviceRequest, instance);
}
}
return execution.execute(serviceRequest, body);
};
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance,
this.loadBalancer);
if (this.transformers != null) {
for (LoadBalancerRequestTransformer transformer : this.transformers) {
serviceRequest = transformer.transformRequest(serviceRequest,
instance);
}
}
return execution.execute(serviceRequest, body);
};
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.loadbalancer;
import org.springframework.cloud.client.ServiceInstance;
@@ -20,14 +21,19 @@ import org.springframework.core.annotation.Order;
import org.springframework.http.HttpRequest;
/**
* Allows applications to transform the load-balanced {@link HttpRequest} given
* the chosen {@link ServiceInstance}.
*
* Allows applications to transform the load-balanced {@link HttpRequest} given the chosen
* {@link ServiceInstance}.
*
* @author Will Tran
*/
@Order(LoadBalancerRequestTransformer.DEFAULT_ORDER)
public interface LoadBalancerRequestTransformer {
public static final int DEFAULT_ORDER = 0;
/**
* Order for the load balancer request tranformer.
*/
int DEFAULT_ORDER = 0;
HttpRequest transformRequest(HttpRequest request, ServiceInstance instance);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2012-2019 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.
@@ -13,31 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.loadbalancer;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for the {@link LoadBalancerClient}.
*
* @author Ryan Baxter
*/
@ConfigurationProperties("spring.cloud.loadbalancer.retry")
public class LoadBalancerRetryProperties {
private boolean enabled = true;
/**
* Returns true if the load balancer should retry failed requests.
* @return True if the load balancer should retry failed requests; false otherwise.
*/
public boolean isEnabled() {
return enabled;
}
private boolean enabled = true;
/**
* Returns true if the load balancer should retry failed requests.
* @return True if the load balancer should retry failed requests; false otherwise.
*/
public boolean isEnabled() {
return this.enabled;
}
/**
* Sets whether the load balancer should retry failed requests.
* @param enabled Whether the load balancer should retry failed requests.
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* Sets whether the load balancer should retry failed requests.
* @param enabled Whether the load balancer should retry failed requests.
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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.client.loadbalancer;
import org.springframework.web.client.RestTemplate;
@@ -6,5 +22,7 @@ import org.springframework.web.client.RestTemplate;
* @author Spencer Gibb
*/
public interface RestTemplateCustomizer {
void customize(RestTemplate restTemplate);
}

View File

@@ -40,29 +40,33 @@ import org.springframework.util.StreamUtils;
public class RetryLoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRetryProperties lbProperties;
private LoadBalancerRequestFactory requestFactory;
private LoadBalancedRetryFactory lbRetryFactory;
public RetryLoadBalancerInterceptor(LoadBalancerClient loadBalancer,
LoadBalancerRetryProperties lbProperties,
LoadBalancerRequestFactory requestFactory,
LoadBalancedRetryFactory lbRetryFactory) {
this.loadBalancer = loadBalancer;
this.lbProperties = lbProperties;
this.requestFactory = requestFactory;
this.lbRetryFactory = lbRetryFactory;
LoadBalancerRetryProperties lbProperties,
LoadBalancerRequestFactory requestFactory,
LoadBalancedRetryFactory lbRetryFactory) {
this.loadBalancer = loadBalancer;
this.lbProperties = lbProperties;
this.requestFactory = requestFactory;
this.lbRetryFactory = lbRetryFactory;
}
}
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
final String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
final LoadBalancedRetryPolicy retryPolicy = lbRetryFactory.createRetryPolicy(serviceName,
loadBalancer);
Assert.state(serviceName != null,
"Request URI does not contain a valid hostname: " + originalUri);
final LoadBalancedRetryPolicy retryPolicy = this.lbRetryFactory
.createRetryPolicy(serviceName, this.loadBalancer);
RetryTemplate template = createRetryTemplate(serviceName, request, retryPolicy);
return template.execute(context -> {
ServiceInstance serviceInstance = null;
@@ -71,41 +75,48 @@ public class RetryLoadBalancerInterceptor implements ClientHttpRequestIntercepto
serviceInstance = lbContext.getServiceInstance();
}
if (serviceInstance == null) {
serviceInstance = loadBalancer.choose(serviceName);
serviceInstance = this.loadBalancer.choose(serviceName);
}
ClientHttpResponse response = RetryLoadBalancerInterceptor.this.loadBalancer.execute(
serviceName, serviceInstance,
requestFactory.createRequest(request, body, execution));
ClientHttpResponse response = RetryLoadBalancerInterceptor.this.loadBalancer
.execute(serviceName, serviceInstance,
this.requestFactory.createRequest(request, body, execution));
int statusCode = response.getRawStatusCode();
if (retryPolicy != null && retryPolicy.retryableStatusCode(statusCode)) {
byte[] bodyCopy = StreamUtils.copyToByteArray(response.getBody());
response.close();
throw new ClientHttpResponseStatusCodeException(serviceName, response, bodyCopy);
throw new ClientHttpResponseStatusCodeException(serviceName, response,
bodyCopy);
}
return response;
}, new LoadBalancedRecoveryCallback<ClientHttpResponse, ClientHttpResponse>() {
//This is a special case, where both parameters to LoadBalancedRecoveryCallback are
//the same. In most cases they would be different.
// This is a special case, where both parameters to
// LoadBalancedRecoveryCallback are
// the same. In most cases they would be different.
@Override
protected ClientHttpResponse createResponse(ClientHttpResponse response, URI uri) {
protected ClientHttpResponse createResponse(ClientHttpResponse response,
URI uri) {
return response;
}
});
}
private RetryTemplate createRetryTemplate(String serviceName, HttpRequest request, LoadBalancedRetryPolicy retryPolicy) {
private RetryTemplate createRetryTemplate(String serviceName, HttpRequest request,
LoadBalancedRetryPolicy retryPolicy) {
RetryTemplate template = new RetryTemplate();
BackOffPolicy backOffPolicy = lbRetryFactory.createBackOffPolicy(serviceName);
template.setBackOffPolicy(backOffPolicy == null ? new NoBackOffPolicy() : backOffPolicy);
BackOffPolicy backOffPolicy = this.lbRetryFactory
.createBackOffPolicy(serviceName);
template.setBackOffPolicy(
backOffPolicy == null ? new NoBackOffPolicy() : backOffPolicy);
template.setThrowLastExceptionOnExhausted(true);
RetryListener[] retryListeners = lbRetryFactory.createRetryListeners(serviceName);
RetryListener[] retryListeners = this.lbRetryFactory
.createRetryListeners(serviceName);
if (retryListeners != null && retryListeners.length != 0) {
template.setListeners(retryListeners);
}
template.setRetryPolicy(
!lbProperties.isEnabled() || retryPolicy == null ? new NeverRetryPolicy()
: new InterceptorRetryPolicy(request, retryPolicy, loadBalancer,
serviceName));
template.setRetryPolicy(!this.lbProperties.isEnabled() || retryPolicy == null
? new NeverRetryPolicy() : new InterceptorRetryPolicy(request,
retryPolicy, this.loadBalancer, serviceName));
return template;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2013-2019 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.client.loadbalancer;
import java.io.IOException;
@@ -20,27 +21,30 @@ import java.net.URI;
/**
* Exception to be thrown when the status code is deemed to be retryable.
*
* @author Ryan Baxter
*/
public class RetryableStatusCodeException extends IOException {
private static final String MESSAGE = "Service %s returned a status code of %d";
private Object response;
private final Object response;
private URI uri;
private final URI uri;
public RetryableStatusCodeException(String serviceId, int statusCode, Object response, URI uri) {
public RetryableStatusCodeException(String serviceId, int statusCode, Object response,
URI uri) {
super(String.format(MESSAGE, serviceId, statusCode));
this.response = response;
this.uri = uri;
}
public Object getResponse() {
return response;
return this.response;
}
public URI getUri() {
return uri;
return this.uri;
}
}

View File

@@ -19,17 +19,18 @@ package org.springframework.cloud.client.loadbalancer;
import org.springframework.cloud.client.ServiceInstance;
/**
* Implemented by classes which use a load balancer to choose a server to
* send a request to.
* Implemented by classes which use a load balancer to choose a server to send a request
* to.
*
* @author Ryan Baxter
*/
public interface ServiceInstanceChooser {
/**
* Chooses a ServiceInstance from the LoadBalancer for the specified service.
* @param serviceId The service ID to look up the LoadBalancer.
* @return A ServiceInstance that matches the serviceId.
*/
ServiceInstance choose(String serviceId);
/**
* Chooses a ServiceInstance from the LoadBalancer for the specified service.
* @param serviceId The service ID to look up the LoadBalancer.
* @return A ServiceInstance that matches the serviceId.
*/
ServiceInstance choose(String serviceId);
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.client.loadbalancer;
import java.net.URI;
@@ -10,11 +26,13 @@ import org.springframework.http.client.support.HttpRequestWrapper;
* @author Ryan Baxter
*/
public class ServiceRequestWrapper extends HttpRequestWrapper {
private final ServiceInstance instance;
private final LoadBalancerClient loadBalancer;
public ServiceRequestWrapper(HttpRequest request, ServiceInstance instance,
LoadBalancerClient loadBalancer) {
LoadBalancerClient loadBalancer) {
super(request);
this.instance = instance;
this.loadBalancer = loadBalancer;
@@ -22,8 +40,8 @@ public class ServiceRequestWrapper extends HttpRequestWrapper {
@Override
public URI getURI() {
URI uri = this.loadBalancer.reconstructURI(
this.instance, getRequest().getURI());
URI uri = this.loadBalancer.reconstructURI(this.instance, getRequest().getURI());
return uri;
}
}

View File

@@ -21,19 +21,11 @@ import org.springframework.core.style.ToStringCreator;
/**
* @author Spencer Gibb
*/
//TODO: add metrics
// TODO: add metrics
public class CompletionContext {
public enum Status {
/** Request was handled successfully */
SUCCESSS,
/** Request reached the server but failed due to timeout or internal error */
FAILED,
/** Request did not go off box and should not be counted for statistics */
DISCARD,
}
private final Status status;
private final Throwable throwable;
public CompletionContext(Status status) {
@@ -46,19 +38,33 @@ public class CompletionContext {
}
public Status getStatus() {
return status;
return this.status;
}
public Throwable getThrowable() {
return throwable;
return this.throwable;
}
@Override
public String toString() {
ToStringCreator to = new ToStringCreator(this);
to.append("status", status);
to.append("throwable", throwable);
to.append("status", this.status);
to.append("throwable", this.throwable);
return to.toString();
}
/**
* Request status state.
*/
public enum Status {
/** Request was handled successfully. */
SUCCESSS,
/** Request reached the server but failed due to timeout or internal error. */
FAILED,
/** Request did not go off box and should not be counted for statistics. */
DISCARD,
}
}

View File

@@ -41,6 +41,7 @@ public class DefaultResponse implements Response<ServiceInstance> {
@Override
public void onComplete(CompletionContext completionContext) {
//TODO: implement
// TODO: implement
}
}

View File

@@ -35,6 +35,7 @@ public class EmptyResponse implements Response<ServiceInstance> {
@Override
public void onComplete(CompletionContext completionContext) {
//TODO: implement
// TODO: implement
}
}

View File

@@ -1,9 +1,27 @@
/*
* Copyright 2012-2019 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.client.loadbalancer.reactive;
import java.net.URI;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpStatus;
@@ -12,8 +30,6 @@ import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeFunction;
import reactor.core.publisher.Mono;
/**
* @author Spencer Gibb
* @author Ryan Baxter
@@ -33,25 +49,30 @@ public class LoadBalancerExchangeFilterFunction implements ExchangeFilterFunctio
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
URI originalUrl = request.url();
String serviceId = originalUrl.getHost();
if(serviceId == null) {
String msg = String.format("Request URI does not contain a valid hostname: %s", originalUrl.toString());
if (serviceId == null) {
String msg = String.format(
"Request URI does not contain a valid hostname: %s",
originalUrl.toString());
logger.warn(msg);
return Mono.just(ClientResponse.create(HttpStatus.BAD_REQUEST).body(msg).build());
return Mono.just(
ClientResponse.create(HttpStatus.BAD_REQUEST).body(msg).build());
}
//TODO: reactive lb client
// TODO: reactive lb client
ServiceInstance instance = this.loadBalancerClient.choose(serviceId);
if(instance == null) {
String msg = String.format("Load balancer does not contain an instance for the service %s", serviceId);
if (instance == null) {
String msg = String.format(
"Load balancer does not contain an instance for the service %s",
serviceId);
logger.warn(msg);
return Mono.just(ClientResponse.create(HttpStatus.SERVICE_UNAVAILABLE).body(msg).build());
return Mono.just(ClientResponse.create(HttpStatus.SERVICE_UNAVAILABLE)
.body(msg).build());
}
URI uri = this.loadBalancerClient.reconstructURI(instance, originalUrl);
ClientRequest newRequest = ClientRequest.method(request.method(), uri)
.headers(headers -> headers.addAll(request.headers()))
.cookies(cookies -> cookies.addAll(request.cookies()))
.attributes(attributes -> attributes.putAll(request.attributes()))
.body(request.body())
.build();
.body(request.body()).build();
return next.exchange(newRequest);
}

View File

@@ -19,20 +19,27 @@ package org.springframework.cloud.client.loadbalancer.reactive;
import org.reactivestreams.Publisher;
/**
* Reactive load balancer.
*
* @param <T> type of the response
* @author Spencer Gibb
*/
public interface ReactiveLoadBalancer<T> {
/**
* Default implementation of a request.
*/
Request REQUEST = new DefaultRequest();
/**
* Choose the next server based on the load balancing algorithm
* @param request
* @return
* Choose the next server based on the load balancing algorithm.
* @param request - incoming request
* @return publisher for the response
*/
Publisher<Response<T>> choose(Request request);
default Publisher<Response<T>> choose() { //conflicting name
default Publisher<Response<T>> choose() { // conflicting name
return choose(REQUEST);
}
}

View File

@@ -1,5 +1,24 @@
/*
* Copyright 2012-2019 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.client.loadbalancer.reactive;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -10,9 +29,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
import java.util.Collections;
import java.util.List;
/**
* @author Spencer Gibb
*/
@@ -26,7 +42,7 @@ public class ReactiveLoadBalancerAutoConfiguration {
private List<WebClient.Builder> webClientBuilders = Collections.emptyList();
public List<WebClient.Builder> getBuilders() {
return webClientBuilders;
return this.webClientBuilders;
}
@Bean
@@ -42,12 +58,15 @@ public class ReactiveLoadBalancerAutoConfiguration {
}
@Bean
public WebClientCustomizer loadbalanceClientWebClientCustomizer(LoadBalancerExchangeFilterFunction filterFunction) {
public WebClientCustomizer loadbalanceClientWebClientCustomizer(
LoadBalancerExchangeFilterFunction filterFunction) {
return builder -> builder.filter(filterFunction);
}
@Bean
public LoadBalancerExchangeFilterFunction loadBalancerExchangeFilterFunction(LoadBalancerClient client) {
public LoadBalancerExchangeFilterFunction loadBalancerExchangeFilterFunction(
LoadBalancerClient client) {
return new LoadBalancerExchangeFilterFunction(client);
}
}

View File

@@ -1,5 +1,28 @@
/*
* Copyright 2012-2019 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.client.loadbalancer.reactive;
/**
* Marker interface for a request.
*
* @author Spencer Gibb
*/
public interface Request {
//TODO: define contents
// TODO: define contents
}

View File

@@ -1,16 +1,37 @@
/*
* Copyright 2012-2019 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.client.loadbalancer.reactive;
/**
* Response created for each request.
*/
*
* @param <T> type of the server
* @author Spencer Gibb
*/
public interface Response<T> {
boolean hasServer();
T getServer();
/**
* Notification that the request completed
* @param completionContext
* Notification that the request completed.
* @param completionContext - completion context
*/
void onComplete(CompletionContext completionContext);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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.
@@ -23,7 +23,8 @@ import org.springframework.web.reactive.function.client.WebClient;
* {@link org.springframework.web.reactive.function.client.WebClient.Builder
* WebClient.Builder}.
*
* See original {@link org.springframework.boot.web.reactive.function.client.WebClientCustomizer}
* See original
* {@link org.springframework.boot.web.reactive.function.client.WebClientCustomizer}
*
* @author Brian Clozel
* @since 2.1.0
@@ -40,4 +41,3 @@ public interface WebClientCustomizer {
void customize(WebClient.Builder webClientBuilder);
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.client.serviceregistry;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -26,14 +42,17 @@ import org.springframework.core.env.Environment;
* TODO: Document the lifecycle.
*
* @param <R> Registration type passed to the {@link ServiceRegistry}.
*
* @author Spencer Gibb
*/
public abstract class AbstractAutoServiceRegistration<R extends Registration>
implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {
implements AutoServiceRegistration, ApplicationContextAware,
ApplicationListener<WebServerInitializedEvent> {
private static final Log logger = LogFactory
.getLog(AbstractAutoServiceRegistration.class);
private final ServiceRegistry<R> serviceRegistry;
private boolean autoStartup = true;
private AtomicBoolean running = new AtomicBoolean(false);
@@ -46,7 +65,6 @@ public abstract class AbstractAutoServiceRegistration<R extends Registration>
private AtomicInteger port = new AtomicInteger(0);
private final ServiceRegistry<R> serviceRegistry;
private AutoServiceRegistrationProperties properties;
@Deprecated
@@ -54,13 +72,14 @@ public abstract class AbstractAutoServiceRegistration<R extends Registration>
this.serviceRegistry = serviceRegistry;
}
protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry, AutoServiceRegistrationProperties properties) {
protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry,
AutoServiceRegistrationProperties properties) {
this.serviceRegistry = serviceRegistry;
this.properties = properties;
}
protected ApplicationContext getContext() {
return context;
return this.context;
}
@Override
@@ -73,8 +92,8 @@ public abstract class AbstractAutoServiceRegistration<R extends Registration>
public void bind(WebServerInitializedEvent event) {
ApplicationContext context = event.getApplicationContext();
if (context instanceof ConfigurableWebServerApplicationContext) {
if ("management".equals(
((ConfigurableWebServerApplicationContext) context).getServerNamespace())) {
if ("management".equals(((ConfigurableWebServerApplicationContext) context)
.getServerNamespace())) {
return;
}
}
@@ -91,12 +110,12 @@ public abstract class AbstractAutoServiceRegistration<R extends Registration>
@Deprecated
protected Environment getEnvironment() {
return environment;
return this.environment;
}
@Deprecated
protected AtomicInteger getPort() {
return port;
return this.port;
}
public boolean isAutoStartup() {
@@ -114,7 +133,8 @@ public abstract class AbstractAutoServiceRegistration<R extends Registration>
// only initialize if nonSecurePort is greater than 0 and it isn't already running
// because of containerPortInitializer below
if (!this.running.get()) {
this.context.publishEvent(new InstancePreRegisteredEvent(this, getRegistration()));
this.context.publishEvent(
new InstancePreRegisteredEvent(this, getRegistration()));
register();
if (shouldRegisterManagement()) {
registerManagement();
@@ -193,7 +213,7 @@ public abstract class AbstractAutoServiceRegistration<R extends Registration>
}
protected AtomicBoolean getRunning() {
return running;
return this.running;
}
public int getOrder() {
@@ -255,4 +275,5 @@ public abstract class AbstractAutoServiceRegistration<R extends Registration>
this.serviceRegistry.close();
}
}
}

View File

@@ -1,7 +1,24 @@
/*
* Copyright 2012-2019 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.client.serviceregistry;
/**
* @author Spencer Gibb
*/
public interface AutoServiceRegistration {
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.client.serviceregistry;
import javax.annotation.PostConstruct;
@@ -23,8 +39,10 @@ public class AutoServiceRegistrationAutoConfiguration {
@PostConstruct
protected void init() {
if (autoServiceRegistration == null && this.properties.isFailFast()) {
throw new IllegalStateException("Auto Service Registration has been requested, but there is no AutoServiceRegistration bean");
if (this.autoServiceRegistration == null && this.properties.isFailFast()) {
throw new IllegalStateException("Auto Service Registration has "
+ "been requested, but there is no AutoServiceRegistration bean");
}
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.client.serviceregistry;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -11,4 +27,5 @@ import org.springframework.context.annotation.Configuration;
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.client.serviceregistry;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -14,11 +30,13 @@ public class AutoServiceRegistrationProperties {
/** Whether to register the management as a service. Defaults to true. */
private boolean registerManagement = true;
/** Whether startup fails if there is no AutoServiceRegistration. Defaults to false. */
/**
* Whether startup fails if there is no AutoServiceRegistration. Defaults to false.
*/
private boolean failFast = false;
public boolean isEnabled() {
return enabled;
return this.enabled;
}
public void setEnabled(boolean enabled) {
@@ -26,23 +44,24 @@ public class AutoServiceRegistrationProperties {
}
public boolean isRegisterManagement() {
return registerManagement;
}
@Deprecated
public boolean shouldRegisterManagement() {
return registerManagement;
return this.registerManagement;
}
public void setRegisterManagement(boolean registerManagement) {
this.registerManagement = registerManagement;
}
@Deprecated
public boolean shouldRegisterManagement() {
return this.registerManagement;
}
public boolean isFailFast() {
return failFast;
return this.failFast;
}
public void setFailFast(boolean failFast) {
this.failFast = failFast;
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.client.serviceregistry;
import org.springframework.cloud.client.ServiceInstance;
@@ -9,4 +25,5 @@ import org.springframework.cloud.client.ServiceInstance;
* @since 1.2.0
*/
public interface Registration extends ServiceInstance {
}

View File

@@ -1,23 +1,40 @@
/*
* Copyright 2012-2019 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.client.serviceregistry;
/**
* Contract to register and deregister instances with a Service Registry.
*
* @param <R> registration meta data
* @author Spencer Gibb
* @since 1.2.0
*/
public interface ServiceRegistry<R extends Registration> {
/**
* Registers the registration. A registration typically has information about
* an instance, such as its hostname and port.
* @param registration The registration.
* Registers the registration. A registration typically has information about an
* instance, such as its hostname and port.
* @param registration registration meta data
*/
void register(R registration);
/**
* Deregisters the registration.
* @param registration
* @param registration registration meta data
*/
void deregister(R registration);
@@ -27,22 +44,21 @@ public interface ServiceRegistry<R extends Registration> {
void close();
/**
* Sets the status of the registration. The status values are determined
* by the individual implementations.
*
* @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
* Sets the status of the registration. The status values are determined by the
* individual implementations.
* @param registration The registration to update.
* @param status The status to set.
* @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
*/
void setStatus(R registration, String status);
/**
* Gets the status of a particular registration.
*
* @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
* @param registration The registration to query.
* @param <T> The type of the status.
* @return The status of the registration.
* @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
*/
<T> T getStatus(R registration);
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.client.serviceregistry;
import org.springframework.beans.factory.annotation.Autowired;
@@ -18,15 +34,20 @@ public class ServiceRegistryAutoConfiguration {
@ConditionalOnBean(ServiceRegistry.class)
@ConditionalOnClass(Endpoint.class)
protected class ServiceRegistryEndpointConfiguration {
@Autowired(required = false)
private Registration registration;
@Bean
@ConditionalOnEnabledEndpoint
public ServiceRegistryEndpoint serviceRegistryEndpoint(ServiceRegistry serviceRegistry) {
ServiceRegistryEndpoint endpoint = new ServiceRegistryEndpoint(serviceRegistry);
endpoint.setRegistration(registration);
public ServiceRegistryEndpoint serviceRegistryEndpoint(
ServiceRegistry serviceRegistry) {
ServiceRegistryEndpoint endpoint = new ServiceRegistryEndpoint(
serviceRegistry);
endpoint.setRegistration(this.registration);
return endpoint;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2012-2019 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.
@@ -12,7 +12,6 @@
* 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.client.serviceregistry.endpoint;
@@ -52,7 +51,8 @@ public class ServiceRegistryEndpoint {
Assert.notNull(status, "status may not by null");
if (this.registration == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("no registration found");
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("no registration found");
}
this.serviceRegistry.setStatus(this.registration, status);
@@ -62,10 +62,12 @@ public class ServiceRegistryEndpoint {
@ReadOperation
public ResponseEntity getStatus() {
if (this.registration == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("no registration found");
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("no registration found");
}
return ResponseEntity.ok().body(this.serviceRegistry.getStatus(this.registration));
return ResponseEntity.ok()
.body(this.serviceRegistry.getStatus(this.registration));
}
}

View File

@@ -1,19 +1,17 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* * Copyright 2013-2016 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.
* 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.commons.httpclient;
@@ -25,11 +23,20 @@ import org.apache.http.conn.HttpClientConnectionManager;
/**
* Interface for creating an {@link HttpClientConnectionManager}.
*
* @author Ryan Baxter
*/
public interface ApacheHttpClientConnectionManagerFactory {
public static final String HTTP_SCHEME = "http";
public static final String HTTPS_SCHEME = "https";
/**
* Scheme for HTTP based communication.
*/
String HTTP_SCHEME = "http";
/**
* Scheme for HTTPS based communication.
*/
String HTTPS_SCHEME = "https";
/**
* Creates a new {@link HttpClientConnectionManager}.
@@ -38,10 +45,12 @@ public interface ApacheHttpClientConnectionManagerFactory {
* @param maxConnectionsPerRoute The total number of connections per route.
* @param timeToLive The time a connection is allowed to exist.
* @param timeUnit The time unit for the time-to-live value.
* @param registryBuilder The {@link RegistryBuilder} to use in the connection manager.
* @param registryBuilder The {@link RegistryBuilder} to use in the connection
* manager.
* @return A new {@link HttpClientConnectionManager}.
*/
public HttpClientConnectionManager newConnectionManager(boolean disableSslValidation,
HttpClientConnectionManager newConnectionManager(boolean disableSslValidation,
int maxTotalConnections, int maxConnectionsPerRoute, long timeToLive,
TimeUnit timeUnit, RegistryBuilder registryBuilder);
}

View File

@@ -1,19 +1,17 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* * Copyright 2013-2016 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.
* 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.commons.httpclient;
@@ -23,13 +21,16 @@ import org.apache.http.impl.client.HttpClientBuilder;
/**
* Factory for creating a new {@link CloseableHttpClient}.
*
* @author Ryan Baxter
*/
public interface ApacheHttpClientFactory {
/**
* Creates an {@link HttpClientBuilder} that can be used to create a new {@link CloseableHttpClient}.
* Creates an {@link HttpClientBuilder} that can be used to create a new
* {@link CloseableHttpClient}.
* @return A {@link HttpClientBuilder}.
*/
public HttpClientBuilder createBuilder();
HttpClientBuilder createBuilder();
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.commons.httpclient;
import java.security.KeyManagementException;
@@ -6,9 +22,12 @@ import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
@@ -18,10 +37,10 @@ import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.commons.logging.Log;
/**
* Default implementation of {@link ApacheHttpClientConnectionManagerFactory}.
*
* @author Ryan Baxter
* @author Michael Wirth
*/
@@ -42,17 +61,17 @@ public class DefaultApacheHttpClientConnectionManagerFactory
int maxTotalConnections, int maxConnectionsPerRoute, long timeToLive,
TimeUnit timeUnit, RegistryBuilder registryBuilder) {
if (registryBuilder == null) {
registryBuilder = RegistryBuilder.<ConnectionSocketFactory> create()
registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create()
.register(HTTP_SCHEME, PlainConnectionSocketFactory.INSTANCE);
}
if (disableSslValidation) {
try {
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null,
new TrustManager[] { new DisabledValidationTrustManager()},
new SecureRandom());
new TrustManager[] { new DisabledValidationTrustManager() },
new SecureRandom());
registryBuilder.register(HTTPS_SCHEME, new SSLConnectionSocketFactory(
sslContext, NoopHostnameVerifier.INSTANCE));
sslContext, NoopHostnameVerifier.INSTANCE));
}
catch (NoSuchAlgorithmException e) {
LOG.warn("Error creating SSLContext", e);
@@ -60,8 +79,10 @@ public class DefaultApacheHttpClientConnectionManagerFactory
catch (KeyManagementException e) {
LOG.warn("Error creating SSLContext", e);
}
} else {
registryBuilder.register("https", SSLConnectionSocketFactory.getSocketFactory());
}
else {
registryBuilder.register("https",
SSLConnectionSocketFactory.getSocketFactory());
}
final Registry<ConnectionSocketFactory> registry = registryBuilder.build();
@@ -74,19 +95,22 @@ public class DefaultApacheHttpClientConnectionManagerFactory
}
class DisabledValidationTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates,
String s) throws CertificateException {
public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates,
String s) throws CertificateException {
public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}

View File

@@ -1,9 +1,26 @@
/*
* Copyright 2012-2019 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.commons.httpclient;
import org.apache.http.impl.client.HttpClientBuilder;
/**
* Default implementation of {@link ApacheHttpClientFactory}.
*
* @author Ryan Baxter
*/
public class DefaultApacheHttpClientFactory implements ApacheHttpClientFactory {
@@ -17,11 +34,12 @@ public class DefaultApacheHttpClientFactory implements ApacheHttpClientFactory {
/**
* A default {@link HttpClientBuilder}. The {@link HttpClientBuilder} returned will
* have content compression disabled, have cookie management disabled, and use system
* properties.
* properties.
*/
@Override
public HttpClientBuilder createBuilder() {
return this.builder.disableContentCompression()
.disableCookieManagement().useSystemProperties();
return this.builder.disableContentCompression().disableCookieManagement()
.useSystemProperties();
}
}

View File

@@ -1,17 +1,37 @@
package org.springframework.cloud.commons.httpclient;
/*
* Copyright 2012-2019 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.
*/
import okhttp3.ConnectionPool;
package org.springframework.cloud.commons.httpclient;
import java.util.concurrent.TimeUnit;
import okhttp3.ConnectionPool;
/**
* Default implementation of {@link OkHttpClientConnectionPoolFactory}.
*
* @author Ryan Baxter
*/
public class DefaultOkHttpClientConnectionPoolFactory implements OkHttpClientConnectionPoolFactory {
public class DefaultOkHttpClientConnectionPoolFactory
implements OkHttpClientConnectionPoolFactory {
@Override
public ConnectionPool create(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
public ConnectionPool create(int maxIdleConnections, long keepAliveDuration,
TimeUnit timeUnit) {
return new ConnectionPool(maxIdleConnections, keepAliveDuration, timeUnit);
}
}

View File

@@ -1,18 +1,36 @@
package org.springframework.cloud.commons.httpclient;
/*
* Copyright 2012-2019 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.
*/
import okhttp3.OkHttpClient;
package org.springframework.cloud.commons.httpclient;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Default implementation of {@link OkHttpClientFactory}.
*
* @author Ryan Baxter
*/
public class DefaultOkHttpClientFactory implements OkHttpClientFactory {
@@ -35,8 +53,9 @@ public class DefaultOkHttpClientFactory implements OkHttpClientFactory {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, new java.security.SecureRandom());
SSLSocketFactory disabledSSLSocketFactory = sslContext.getSocketFactory();
builder.sslSocketFactory(disabledSSLSocketFactory, disabledTrustManager);
builder.hostnameVerifier(new TrustAllHostnames());
this.builder.sslSocketFactory(disabledSSLSocketFactory,
disabledTrustManager);
this.builder.hostnameVerifier(new TrustAllHostnames());
}
catch (NoSuchAlgorithmException e) {
LOG.warn("Error setting SSLSocketFactory in OKHttpClient", e);
@@ -45,6 +64,7 @@ public class DefaultOkHttpClientFactory implements OkHttpClientFactory {
LOG.warn("Error setting SSLSocketFactory in OKHttpClient", e);
}
}
return builder;
return this.builder;
}
}

View File

@@ -1,9 +1,25 @@
/*
* Copyright 2012-2019 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.commons.httpclient;
import okhttp3.OkHttpClient;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -35,9 +51,11 @@ public class HttpClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ApacheHttpClientFactory apacheHttpClientFactory(HttpClientBuilder builder) {
public ApacheHttpClientFactory apacheHttpClientFactory(
HttpClientBuilder builder) {
return new DefaultApacheHttpClientFactory(builder);
}
}
@Configuration
@@ -62,5 +80,7 @@ public class HttpClientConfiguration {
public OkHttpClientFactory okHttpClientFactory(OkHttpClient.Builder builder) {
return new DefaultOkHttpClientFactory(builder);
}
}
}

View File

@@ -1,11 +1,28 @@
package org.springframework.cloud.commons.httpclient;
/*
* Copyright 2012-2019 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.
*/
import okhttp3.ConnectionPool;
package org.springframework.cloud.commons.httpclient;
import java.util.concurrent.TimeUnit;
import okhttp3.ConnectionPool;
/**
* Creates {@link ConnectionPool}s for {@link okhttp3.OkHttpClient}s.
*
* @author Ryan Baxter
*/
public interface OkHttpClientConnectionPoolFactory {
@@ -17,5 +34,7 @@ public interface OkHttpClientConnectionPoolFactory {
* @param timeUnit The time unit for the keep-alive duration.
* @return A new {@link ConnectionPool}.
*/
public ConnectionPool create(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit);
ConnectionPool create(int maxIdleConnections, long keepAliveDuration,
TimeUnit timeUnit);
}

View File

@@ -1,15 +1,33 @@
package org.springframework.cloud.commons.httpclient;
/*
* Copyright 2012-2019 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.
*/
import okhttp3.OkHttpClient;
package org.springframework.cloud.commons.httpclient;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
/**
* Creates new {@link OkHttpClient}s.
*
* @author Ryan Baxter
*/
public interface OkHttpClientFactory {
@@ -19,33 +37,40 @@ public interface OkHttpClientFactory {
* @param disableSslValidation Disables SSL validation
* @return A new {@link OkHttpClient.Builder}
*/
public OkHttpClient.Builder createBuilder(boolean disableSslValidation);
OkHttpClient.Builder createBuilder(boolean disableSslValidation);
/**
* A {@link X509TrustManager} that does not validate SSL certificates.
*/
public static class DisableValidationTrustManager implements X509TrustManager {
class DisableValidationTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}
public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
/**
* A {@link HostnameVerifier} that does not validate any hostnames.
*/
public static class TrustAllHostnames implements HostnameVerifier {
class TrustAllHostnames implements HostnameVerifier {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.commons.util;
import org.springframework.core.env.PropertyResolver;
@@ -6,15 +22,20 @@ import org.springframework.util.StringUtils;
/**
* @author Spencer Gibb
*/
public class IdUtils {
public final class IdUtils {
private static final String SEPARATOR = ":";
public static String getDefaultInstanceId(PropertyResolver resolver) {
return getDefaultInstanceId(resolver, true);
}
private IdUtils() {
throw new IllegalStateException("Can't instantiate a utility class");
}
public static String getDefaultInstanceId(PropertyResolver resolver, boolean includeHostname) {
public static String getDefaultInstanceId(PropertyResolver resolver) {
return getDefaultInstanceId(resolver, true);
}
public static String getDefaultInstanceId(PropertyResolver resolver,
boolean includeHostname) {
String vcapInstanceId = resolver.getProperty("vcap.application.instance_id");
if (StringUtils.hasText(vcapInstanceId)) {
return vcapInstanceId;
@@ -34,13 +55,16 @@ public class IdUtils {
return combineParts(namePart, SEPARATOR, indexPart);
}
public static String combineParts(String firstPart, String separator, String secondPart) {
public static String combineParts(String firstPart, String separator,
String secondPart) {
String combined = null;
if (firstPart != null && secondPart != null) {
combined = firstPart + separator + secondPart;
} else if (firstPart != null) {
}
else if (firstPart != null) {
combined = firstPart;
} else if (secondPart != null) {
}
else if (secondPart != null) {
combined = secondPart;
}
return combined;

View File

@@ -25,11 +25,9 @@ import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
@@ -42,24 +40,24 @@ public class InetUtils implements Closeable {
// TODO: maybe shutdown the thread pool if it isn't being used?
private final ExecutorService executorService;
private final InetUtilsProperties properties;
private final Log log = LogFactory.getLog(InetUtils.class);
public InetUtils(final InetUtilsProperties properties) {
this.properties = properties;
this.executorService = Executors
.newSingleThreadExecutor(r -> {
Thread thread = new Thread(r);
thread.setName(InetUtilsProperties.PREFIX);
thread.setDaemon(true);
return thread;
});
this.executorService = Executors.newSingleThreadExecutor(r -> {
Thread thread = new Thread(r);
thread.setName(InetUtilsProperties.PREFIX);
thread.setDaemon(true);
return thread;
});
}
@Override
public void close() {
executorService.shutdown();
this.executorService.shutdown();
}
public HostInfo findFirstNonLoopbackHostInfo() {
@@ -81,7 +79,7 @@ public class InetUtils implements Closeable {
.getNetworkInterfaces(); nics.hasMoreElements();) {
NetworkInterface ifc = nics.nextElement();
if (ifc.isUp()) {
log.trace("Testing interface: " + ifc.getDisplayName());
this.log.trace("Testing interface: " + ifc.getDisplayName());
if (ifc.getIndex() < lowest || result == null) {
lowest = ifc.getIndex();
}
@@ -97,7 +95,7 @@ public class InetUtils implements Closeable {
if (address instanceof Inet4Address
&& !address.isLoopbackAddress()
&& isPreferredAddress(address)) {
log.trace("Found non-loopback interface: "
this.log.trace("Found non-loopback interface: "
+ ifc.getDisplayName());
result = address;
}
@@ -108,7 +106,7 @@ public class InetUtils implements Closeable {
}
}
catch (IOException ex) {
log.error("Cannot get first non-loopback address", ex);
this.log.error("Cannot get first non-loopback address", ex);
}
if (result != null) {
@@ -119,18 +117,19 @@ public class InetUtils implements Closeable {
return InetAddress.getLocalHost();
}
catch (UnknownHostException e) {
log.warn("Unable to retrieve localhost");
this.log.warn("Unable to retrieve localhost");
}
return null;
}
/** For testing. */ boolean isPreferredAddress(InetAddress address) {
// For testing.
boolean isPreferredAddress(InetAddress address) {
if (this.properties.isUseOnlySiteLocalInterfaces()) {
final boolean siteLocalAddress = address.isSiteLocalAddress();
if (!siteLocalAddress) {
log.trace("Ignoring address: " + address.getHostAddress());
this.log.trace("Ignoring address: " + address.getHostAddress());
}
return siteLocalAddress;
}
@@ -144,14 +143,15 @@ public class InetUtils implements Closeable {
return true;
}
}
log.trace("Ignoring address: " + address.getHostAddress());
this.log.trace("Ignoring address: " + address.getHostAddress());
return false;
}
/** For testing. */ boolean ignoreInterface(String interfaceName) {
// For testing
boolean ignoreInterface(String interfaceName) {
for (String regex : this.properties.getIgnoredInterfaces()) {
if (interfaceName.matches(regex)) {
log.trace("Ignoring interface: " + interfaceName);
this.log.trace("Ignoring interface: " + interfaceName);
return true;
}
}
@@ -160,14 +160,14 @@ public class InetUtils implements Closeable {
public HostInfo convertAddress(final InetAddress address) {
HostInfo hostInfo = new HostInfo();
Future<String> result = executorService.submit(address::getHostName);
Future<String> result = this.executorService.submit(address::getHostName);
String hostname;
try {
hostname = result.get(this.properties.getTimeoutSeconds(), TimeUnit.SECONDS);
}
catch (Exception e) {
log.info("Cannot determine local hostname");
this.log.info("Cannot determine local hostname");
hostname = "localhost";
}
hostInfo.setHostname(hostname);
@@ -175,9 +175,18 @@ public class InetUtils implements Closeable {
return hostInfo;
}
/**
* Host information pojo.
*/
public static class HostInfo {
/**
* Should override the host info.
*/
public boolean override;
private String ipAddress;
private String hostname;
public HostInfo(String hostname) {
@@ -203,7 +212,7 @@ public class InetUtils implements Closeable {
}
public boolean isOverride() {
return override;
return this.override;
}
public void setOverride(boolean override) {
@@ -211,7 +220,7 @@ public class InetUtils implements Closeable {
}
public String getIpAddress() {
return ipAddress;
return this.ipAddress;
}
public void setIpAddress(String ipAddress) {
@@ -219,12 +228,13 @@ public class InetUtils implements Closeable {
}
public String getHostname() {
return hostname;
return this.hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -24,10 +24,16 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Properties for {@link InetUtils}.
*
* @author Spencer Gibb
*/
@ConfigurationProperties(InetUtilsProperties.PREFIX)
public class InetUtilsProperties {
/**
* Prefix for the Inet Utils properties.
*/
public static final String PREFIX = "spring.cloud.inetutils";
/**
@@ -50,13 +56,13 @@ public class InetUtilsProperties {
* List of Java regular expressions for network interfaces that will be ignored.
*/
private List<String> ignoredInterfaces = new ArrayList<>();
/**
* Whether to use only interfaces with site local addresses.
* See {@link InetAddress#isSiteLocalAddress()} for more details.
* Whether to use only interfaces with site local addresses. See
* {@link InetAddress#isSiteLocalAddress()} for more details.
*/
private boolean useOnlySiteLocalInterfaces = false;
/**
* List of Java regular expressions for network addresses that will be preferred.
*/
@@ -67,7 +73,7 @@ public class InetUtilsProperties {
}
public String getDefaultHostname() {
return defaultHostname;
return this.defaultHostname;
}
public void setDefaultHostname(String defaultHostname) {
@@ -75,7 +81,7 @@ public class InetUtilsProperties {
}
public String getDefaultIpAddress() {
return defaultIpAddress;
return this.defaultIpAddress;
}
public void setDefaultIpAddress(String defaultIpAddress) {
@@ -83,7 +89,7 @@ public class InetUtilsProperties {
}
public int getTimeoutSeconds() {
return timeoutSeconds;
return this.timeoutSeconds;
}
public void setTimeoutSeconds(int timeoutSeconds) {
@@ -91,7 +97,7 @@ public class InetUtilsProperties {
}
public List<String> getIgnoredInterfaces() {
return ignoredInterfaces;
return this.ignoredInterfaces;
}
public void setIgnoredInterfaces(List<String> ignoredInterfaces) {
@@ -99,7 +105,7 @@ public class InetUtilsProperties {
}
public boolean isUseOnlySiteLocalInterfaces() {
return useOnlySiteLocalInterfaces;
return this.useOnlySiteLocalInterfaces;
}
public void setUseOnlySiteLocalInterfaces(boolean useOnlySiteLocalInterfaces) {
@@ -107,10 +113,11 @@ public class InetUtilsProperties {
}
public List<String> getPreferredNetworks() {
return preferredNetworks;
return this.preferredNetworks;
}
public void setPreferredNetworks(List<String> preferredNetworks) {
this.preferredNetworks = preferredNetworks;
}
}

View File

@@ -22,6 +22,7 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.DeferredImportSelector;
@@ -32,25 +33,25 @@ import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
/**
* Selects configurations to load, defined by the generic type T. Loads implementations
* using {@link SpringFactoriesLoader}.
*
* @param <T> type of annotation class
* @author Spencer Gibb
* @author Dave Syer
*/
public abstract class SpringFactoryImportSelector<T>
implements DeferredImportSelector, BeanClassLoaderAware, EnvironmentAware {
private final Log log = LogFactory.getLog(SpringFactoryImportSelector.class);
private ClassLoader beanClassLoader;
private Class<T> annotationClass;
private Environment environment;
private final Log log = LogFactory.getLog(SpringFactoryImportSelector.class);
@SuppressWarnings("unchecked")
protected SpringFactoryImportSelector() {
this.annotationClass = (Class<T>) GenericTypeResolver
@@ -80,7 +81,7 @@ public abstract class SpringFactoryImportSelector<T>
if (factories.size() > 1) {
// there should only ever be one DiscoveryClient, but there might be more than
// one factory
log.warn("More than one implementation " + "of @" + getSimpleName()
this.log.warn("More than one implementation " + "of @" + getSimpleName()
+ " (now relying on @Conditionals to pick one): " + factories);
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2012-2019 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.commons.util;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
@@ -26,4 +42,5 @@ public class UtilAutoConfiguration {
public InetUtils inetUtils(InetUtilsProperties properties) {
return new InetUtils(properties);
}
}

Some files were not shown because too many files have changed in this diff Show More