[英]How to add custom restTemplate istance into RestTemplateEurekaHttpClient
My intention is to replace Jersey implementation of eureka client with the one provided with a Spring restTemplate.我的目的是用 Spring restTemplate 提供的那个替换 eureka 客户端的 Jersey 实现。
Then, replace the standard implementation of the rest template with one that trust all certificates (i know it's not raccomanded but it doesn't matter right now) in order to register my service to a secure (https) eureka server.然后,将 rest 模板的标准实现替换为信任所有证书的模板(我知道它不是 raccomanded 但现在无关紧要),以便将我的服务注册到安全 (https) eureka 服务器。
I'm using Spring boot 2.2.1-RELEASE and Spring cloud Hoxton.RC2.我正在使用 Spring boot 2.2.1-RELEASE 和 Spring cloud Hoxton.RC2。
According to the official documentation in a spring boot project declaring eureka client this way根据 spring boot 项目中的官方文档,以这种方式声明 eureka 客户端
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client4</artifactId>
</exclusion>
</exclusions>
</dependency>
force the application to use a RestTemplate as the Eureka Client.强制应用程序使用 RestTemplate 作为 Eureka 客户端。
I Already have a custom RestTemplate implementation in my application, lets call it RestTemplateImpl , i'll omit implementation code cause it's irrelevant.我的应用程序中已经有一个自定义 RestTemplate 实现,我们称之为RestTemplateImpl ,我将省略实现代码,因为它无关紧要。
When the application start i was expectin my RestTemplateImpl to be injected as the deafault eureka client implementation, but it wasn't.当应用程序启动时,我希望我的 RestTemplateImpl 作为默认的 eureka 客户端实现被注入,但事实并非如此。
As the exception says正如例外所说
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://localhost:3000/eureka/apps/MY-API": java.security.cert.CertificateException: No name matching localhost found; nested exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:751) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:677) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:586) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient.register(RestTemplateEurekaHttpClient.java:73) ~[spring-cloud-netflix-eureka-client-2.2.0.RC2.jar:2.2.0.RC2]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) [eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient.executeOnNewServer(RedirectingEurekaHttpClient.java:118) ~[eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient.execute(RedirectingEurekaHttpClient.java:79) ~[eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) [eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) [eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:120) [eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) [eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) [eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77) [eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) [eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.DiscoveryClient.register(DiscoveryClient.java:847) [eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.InstanceInfoReplicator.run(InstanceInfoReplicator.java:121) [eureka-client-1.9.13.jar:1.9.13]
at com.netflix.discovery.InstanceInfoReplicator$1.run(InstanceInfoReplicator.java:101) [eureka-client-1.9.13.jar:1.9.13]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_212]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_212]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_212]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_212]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_212]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_212]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_212]
Spring uses a RestTemplateEurekaHttpClient . Spring 使用RestTemplateEurekaHttpClient 。
Looking into the source code i found no way to inject my RestTemplateImpl in favor of the one existing.查看源代码,我发现无法注入我的RestTemplateImpl以支持现有的。
public class RestTemplateTransportClientFactory implements TransportClientFactory {
@Override
public EurekaHttpClient newClient(EurekaEndpoint serviceUrl) {
return new RestTemplateEurekaHttpClient(restTemplate(serviceUrl.getServiceUrl()),
serviceUrl.getServiceUrl());
}
private RestTemplate restTemplate(String serviceUrl) {
RestTemplate restTemplate = new RestTemplate();
try {
URI serviceURI = new URI(serviceUrl);
if (serviceURI.getUserInfo() != null) {
String[] credentials = serviceURI.getUserInfo().split(":");
if (credentials.length == 2) {
restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor(
credentials[0], credentials[1]));
}
}
}
catch (URISyntaxException ignore) {
}
restTemplate.getMessageConverters().add(0, mappingJacksonHttpMessageConverter());
restTemplate.setErrorHandler(new ErrorHandler());
return restTemplate;
}
.....
Please...help me solve this problem...请...帮我解决这个问题...
This can be done in the following way, though it's not recommended for production use这可以通过以下方式完成,但不建议用于生产用途
have your custom RestTemplateTransportClientFactory implementation, for example use the following code, (used eureka-client-1.9.17 and spring 2.2.2.RELEASE)有您的自定义 RestTemplateTransportClientFactory 实现,例如使用以下代码,(使用 eureka-client-1.9.17 和 spring 2.2.2.RELEASE)
@Bean
public RestTemplateDiscoveryClientOptionalArgs discoveryClientOptionalArgs() throws Exception {
RestTemplateDiscoveryClientOptionalArgs args = new RestTemplateDiscoveryClientOptionalArgs();
args.setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
args.setTransportClientFactories(new CustomRestTemplateTransportClientFactories());
return args;
}
public class CustomRestTemplateTransportClientFactories extends RestTemplateTransportClientFactories {
@Override
public TransportClientFactory newTransportClientFactory(final EurekaClientConfig clientConfig,
final Collection<Void> additionalFilters, final InstanceInfo myInstanceInfo,
final Optional<SSLContext> sslContext, final Optional<HostnameVerifier> hostnameVerifier) {
return new CustomRestTemplateTransportClientFactory();
}
}
public class CustomRestTemplateTransportClientFactory extends RestTemplateTransportClientFactory {
@Override
public EurekaHttpClient newClient(EurekaEndpoint serviceUrl) {
try {
return new RestTemplateEurekaHttpClient(restTemplate(serviceUrl.getServiceUrl()),
serviceUrl.getServiceUrl());
}
catch (HttpClientException e) {
e.printStackTrace();
}
return null;
}
private RestTemplate restTemplate(String serviceUrl) throws HttpClientException {
/*
* Inject your custom rest template
*/
RestTemplate restTemplate = restTemplateConfig.restTemplate(null);
try {
URI serviceURI = new URI(serviceUrl);
if (serviceURI.getUserInfo() != null) {
String[] credentials = serviceURI.getUserInfo().split(":");
if (credentials.length == 2) {
restTemplate.getInterceptors()
.add(new BasicAuthenticationInterceptor(credentials[0], credentials[1]));
}
}
}
catch (URISyntaxException ignore) {
}
restTemplate.getMessageConverters().add(0, mappingJacksonHttpMessageConverter());
restTemplate.setErrorHandler(new ErrorHandler());
return restTemplate;
}
}
class ErrorHandler extends DefaultResponseErrorHandler {
@Override
protected boolean hasError(HttpStatus statusCode) {
/**
* When the Eureka server restarts and a client tries to sent a
* heartbeat the server will respond with a 404. By default
* RestTemplate will throw an exception in this case. What we want
* is to return the 404 to the upstream code so it will send another
* registration request to the server.
*/
if (statusCode.is4xxClientError()) {
return false;
}
return super.hasError(statusCode);
}
}
Hope this will be helpful.希望这会有所帮助。 Thanks.谢谢。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.