Spring Cloud RestTemplate @LoadBalanced 支持ip、域名、服务名调用

Spring Cloud项目中使用RestTemplate调用接口,

如果使用时通过域名或者 ip:port 调用,例如

restTemplate.getForObject("https://fanyi.baidu.com/#en/zh/additional", String.class)

java.lang.IllegalStateException: No instances available for fanyi.baidu.com
    at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.execute(RibbonLoadBalancerClient.java:105) ~[spring-cloud-netflix-ribbon-2.1.0.RELEASE.jar:2.1.0.RELEASE]
    at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.execute(RibbonLoadBalancerClient.java:93) ~[spring-cloud-netflix-ribbon-2.1.0.RELEASE.jar:2.1.0.RELEASE]
    at org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor.intercept(LoadBalancerInterceptor.java:55) ~[spring-cloud-commons-2.1.0.RELEASE.jar:2.1.0.RELEASE]

官方针对这种情况给出的方案是创建两个 RestTemplate,在不同的的情况下区分使用

@Configuration
public class MyConfiguration {

    @LoadBalanced
    @Bean
    RestTemplate loadBalanced() {
        return new RestTemplate();
    }

    @Primary
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

public class MyClass {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    @LoadBalanced
    private RestTemplate loadBalanced;

    public String doOtherStuff() {
        return loadBalanced.getForObject("http://stores/stores", String.class);
    }

    public String doStuff() {
        return restTemplate.getForObject("http://example.com", String.class);
    }
}

@See https://cloud.spring.io/spring-cloud-static/spring-cloud-commons/2.0.3.RELEASE/single/spring-cloud-commons.html#_multiple_resttemplate_objects

但是这样还是有点麻烦,比如正式环境由于部署了多份,需要使用服务名称调用,但是在测试环境或者开发环境,只是使用ip+端口调用。

可以使用拦截器。
在 “LoadBalancerInterceptor”(参见:LoadBalancerAutoConfiguration)之前添加自定的 “MixLoadBalancerInterceptor”,拦截处理域名、ip 方式调用

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;

import MixLoadBalancerInterceptor;

@Configuration
public class LoadBalancedRestTemplateConfig {

    @Bean
    public SmartInitializingSingleton mixLoadBalancedRestTemplateInitializer(
            @Autowired List<RestTemplate> restTemplates,
            @Autowired MixLoadBalancerInterceptor mixLoadBalancerInterceptor) {
        return () -> {
            for (RestTemplate restTemplate : restTemplates) {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
                list.add(mixLoadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            }
        };
    }

    @Bean
    public MixLoadBalancerInterceptor mixLoadBalancerInterceptor(@Autowired ClientHttpRequestFactory clientHttpRequestFactory) {
        return new MixLoadBalancerInterceptor(clientHttpRequestFactory);
    }

}
import java.io.IOException;
import java.net.URI;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.PriorityOrdered;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.http.StreamingHttpOutputMessage;
import org.springframework.http.client.*;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;

public class MixLoadBalancerInterceptor implements ClientHttpRequestInterceptor, PriorityOrdered {

    @Value("${mix.loadbalancer.ip.regex:(((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?))}")
    private String ipRegex;

    @Value("${mix.loadbalancer.domain.regex:.*\\.(com|xyz|net|top|tech|org|gov|edu|pub|cn|biz|cc|tv|info|im)}")
    private String domainRegex;

    @Value("${mix.loadbalancer.additional.regex:}")
    private String additionalRegex;


    private ClientHttpRequestFactory httpRequestFactory;

    public MixLoadBalancerInterceptor(ClientHttpRequestFactory httpRequestFactory) {
        this.httpRequestFactory = httpRequestFactory;
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, 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);
        // 判断是否为ip、域名
        if (serviceName.matches(String.format("^%s|%s|%s$", ipRegex, domainRegex, additionalRegex))) {
            // 实际http请求,这段拷贝于:InterceptingClientHttpRequest
            HttpMethod method = request.getMethod();
            Assert.state(method != null, "No standard HTTP method");
            ClientHttpRequest delegate = httpRequestFactory.createRequest(request.getURI(), method);
            request.getHeaders().forEach((key, value) -> delegate.getHeaders().addAll(key, value));
            if (body.length > 0) {
                if (delegate instanceof StreamingHttpOutputMessage) {
                    StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;
                    streamingOutputMessage.setBody(outputStream -> StreamUtils.copy(body, outputStream));
                }
                else {
                    StreamUtils.copy(body, delegate.getBody());
                }
            }
            return delegate.execute();
        }
        else {
            // 如果非ip、域名,继续走@LoadBalanced的原逻辑
            return execution.execute(request, body);
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

启动项目是报错,LoadBalancedRestTemplateConfig required a bean of type 'org.springframework.http.client.ClientHttpRequestFactory' that could not be found.

解决方式如下:

@Configuration
public class RestTemplateConfig {

    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory() {
        return new HttpComponentsClientHttpRequestFactory();
    }

}

经过测试,支持服务名称、域名及IP调用。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇