使用细节
针对@LoadBalanced下的RestTemplate的使用,我总结如下细节供以参考:
- 传入的String类型的url必须是绝对路径(http://...),否则抛出异常:java.lang.IllegalArgumentException: URI is not absolute
- serviceId不区分大小写(http://user/...效果同http://USER/...)
- serviceId后请不要跟port端口号了~~~
最后,需要特别指出的是:标注有@LoadBalanced的RestTemplate只能书写serviceId而不能再写IP地址/域名去发送请求了。若你的项目中两种case都有需要,请定义多个RestTemplate分别应对不同的使用场景~
本地测试
了解了它的执行流程后,若需要本地测试(不依赖于注册中心),可以这么来做:
// 因为自动配置头上有@ConditionalOnMissingBean注解,所以自定义一个覆盖它的行为即可 // 此处复写它的getServer()方法,返回一个固定的(访问百度首页)即可,方便测试 @Bean public LoadBalancerClient loadBalancerClient(SpringClientFactory factory) { return new RibbonLoadBalancerClient(factory) { @Override protected Server getServer(ILoadBalancer loadBalancer, Object hint) { return new Server("www.baidu.com", 80); } }; }
这么一来,下面这个访问结果就是百度首页的html内容喽。
@Test public void contextLoads() { String obj = restTemplate.getForObject("http://my-serviceId", String.class); System.out.println(obj); }
此处my-serviceId肯定是不存在的,但得益于我上面自定义配置的LoadBalancerClient
什么,写死return一个Server实例不优雅?确实,总不能每次上线前还把这部分代码给注释掉吧,若有多个实例呢?还得自己写负载均衡算法吗?很显然Spring Cloud早早就为我们考虑到了这一点:脱离Eureka使用配置listOfServers进行客户端负载均衡调度(<clientName>.<nameSpace>.listOfServers=<comma delimited hostname:port strings>)
对于上例我只需要在主配置文件里这么配置一下:
# ribbon.eureka.enabled=false # 若没用euraka,此配置可省略。否则不可以 my-serviceId.ribbon.listOfServers=www.baidu.com # 若有多个实例请用逗号分隔
效果完全同上。
Tips:这种配置法不需要是完整的绝对路径,
http://
是可以省略的(new Server()
方式亦可)
自己添加一个记录请求日志的拦截器可行吗?
显然是可行的,我给出示例如下:
@LoadBalanced @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); List<ClientHttpRequestInterceptor> list = new ArrayList<>(); list.add((request, body, execution) -> { System.out.println("当前请求的URL是:" + request.getURI().toString()); return execution.execute(request, body); }); restTemplate.setInterceptors(list); return restTemplate; }
这样每次客户端的请求都会打印这句话:当前请求的URI是:http://my-serviceId,一般情况(缺省情况)自定义的拦截器都会在负载均衡拦截器前面执行(因为它要执行最终的请求)。若你有必要定义多个拦截器且要控制顺序,可通过Ordered系列接口来实现~
最后的最后,我抛出一个非常非常重要的问题:
@LoadBalanced @Autowired(required = false) private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired + @LoadBalanced能把你配置的RestTemplate自动注入进来拿来定制呢???核心原理是什么?
提示:本原理内容属于Spring Framwork核心技术,建议深入思考而不囫囵吞枣。有疑问的可以给我留言,我也将会在下篇文章给出详细解答(建议先思考)
推荐阅读
RestTemplate的使用和原理你都烂熟于胸了吗?【享学Spring MVC】
@Qualifier高级应用—按类别批量依赖注入【享学Spring】
总结
本文以大家熟悉的@LoadBalanced和RestTemplate为切入点介绍了Ribbon实现负载均衡的执行流程,当然此部分对Ribbon整个的核心负载体系知识来说知识冰山一角,但它作为敲门砖还是很有意义的,希望本文能勾起你对Ribbon体系的兴趣,深入了解它~