前提

在阅读这篇博客之前,希望你对SpringCloud套件熟悉和理解,更希望关注下微服务开发平台

概述

在使用springcloud ribbon客户端负载均衡的时候,可以给RestTemplate bean 加一个@LoadBalanced注解,就能让这个RestTemplate在请求时拥有客户端负载均衡的能力,先前有细嚼过但是没有做过笔记,刚好处理此类问题记录下

@LoadBalanced

/**
* 注释将RestTemplate bean标记为配置为使用LoadBalancerClient。
*/
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}

通过源码可以发现这是一个LoadBalanced标记注解并且标记了@Qualifier(基于Spring Boot的自动配置机制),我们可以溯源到LoadBalancerAutoConfiguration

LoadBalancerAutoConfiguration

/**
* 功能区的自动配置(客户端负载平衡)
*/
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration { @LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList(); //这里持有@LoadBalanced标记的RestTemplate实例 @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) {
//为restTemplate添加定制
customizer.customize(restTemplate);
}
}
});
} // ... /**
* 以下针对classpath存在RetryTemplate.class的情况配置,先忽略
*/
@Configuration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryAutoConfiguration { @Bean
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryFactory() {
return new LoadBalancedRetryFactory() {
};
}
} // ...
}

@LoadBalanced@Autowried结合使用,意思就是这里注入的RestTempate Bean是所有加有@LoadBalanced注解标记的(持有@LoadBalanced标记的RestTemplate实例)

这段自动装配的代码的含义不难理解,就是利用了RestTempllate的拦截器,使用RestTemplateCustomizer对所有标注了@LoadBalanced的RestTemplate Bean添加了一个LoadBalancerInterceptor拦截器,而这个拦截器的作用就是对请求的URI进行转换获取到具体应该请求哪个服务实例ServiceInstance。

关键问下自己:为什么?

  • RestTemplate实例是怎么被收集的?
  • 怎样通过负载均衡规则获取具体的具体的server?

继续扒看源码>

上面可以看出,会LoadBalancerAutoConfiguration类对我们加上@LoadBalanced注解的bean 添加loadBalancerInterceptor拦截器

LoadBalancerInterceptor

/**
* 功能区的自动配置(客户端负载平衡)。
*/
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor { private LoadBalancerClient loadBalancer; private LoadBalancerRequestFactory requestFactory; public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
} public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
// for backwards compatibility
this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
} @Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
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,
this.requestFactory.createRequest(request, body, execution));
} }

重点看intercept方法 当我们restTemplate执行请求操作时,就会被拦截器拦截进入intercept方法,而loadBalancer是LoadBalancerClient的具体实现

RibbonLoadBalancerClient

	public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer, hint);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonServer ribbonServer = new RibbonServer(serviceId, server,
isSecure(server, serviceId),
serverIntrospector(serviceId).getMetadata(server)); return execute(serviceId, ribbonServer, request);
}

看到这里相信都遇到过类似的错误,恍然大悟

No instances available for  xxxxx

总结

  • 1.根据serviceId 获取对应的loadBalancer
  • 2.根据loadBalancer获取具体的server(这里根据负载均衡规则,获取到具体的服务实例)
  • 3.创建RibbonServer
  • 4.执行具体请求

这里

注意: @LoadBalanced 标记注解获取到最后通过负载均衡规则获取具体的具体的server来发起请求

案例

/**
* 服务注册中心配置
*
* @author <a href="mailto:shangzhi.ibyte@gmail.com">iByte</a>
* @since 1.0.1
*/
@Configuration
@EnableConfigurationProperties(ModuleMappingHelper.class)
public class DiscoveryConfig {
@Autowired
Environment environment; /**
* DiscoveryHeaderHelper默认bean
* @return
*/
@Bean
public DiscoveryHeaderHelper discoveryHeaderHelper() {
DiscoveryHeaderHelper discoveryHeaderHelper = new DiscoveryHeaderHelper(environment);
DiscoveryHeaderHelper.INSTANCE = discoveryHeaderHelper;
return discoveryHeaderHelper;
} /**
* resttemplate构建
*/
@Resource
private RestTemplateBuilder restTemplateBuilder; /**
* resttemplate请求bean,更改系统本身的builder
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
RestTemplate restTemplate = restTemplateBuilder.configure(new RestTemplate());
//RestTemplate interceptors 远程调用请求增加头部信息处理
restTemplate.getInterceptors().add(new RestApiHeaderInterceptor());
//RestTemplate Set the error handler 错误处理
restTemplate.setErrorHandler(new RestResponseErrorHandler());
return restTemplate;
} @Bean
public DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs() {
DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs = new DiscoveryClient.DiscoveryClientOptionalArgs();
discoveryClientOptionalArgs.setAdditionalFilters(Collections.singletonList(new DiscoveryHeaderClientFilter()));
discoveryClientOptionalArgs.setEventListeners(Collections.singleton(new EurekaClientEventListener()));
return discoveryClientOptionalArgs;
}
}

源码地址 > DiscoveryConfig

深入理解@LoadBalanced注解的实现原理与客户端负载均衡的更多相关文章

  1. 为何一个@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?【享学Spring Cloud】

    每篇一句 你应该思考:为什么往往完成比完美更重要? 前言 在Spring Cloud微服务应用体系中,远程调用都应负载均衡.我们在使用RestTemplate作为远程调用客户端的时候,开启负载均衡极其 ...

  2. Spring Cloud(十四):Ribbon实现客户端负载均衡及其实现原理介绍

    年后到现在一直很忙,都没什么时间记录东西了,其实之前工作中积累了很多知识点,一直都堆在备忘录里,只是因为近几个月经历了一些事情,没有太多的经历来写了,但是一些重要的东西,我还是希望能坚持记录下来.正好 ...

  3. Ribbon使用及其客户端负载均衡实现原理分析

    1.ribbon负载均衡测试 (1)consumer工程添加依赖 <dependency> <groupId>org.springframework.cloud</gro ...

  4. Nginx 负载均衡原理简介与负载均衡配置详解

    Nginx负载均衡原理简介与负载均衡配置详解   by:授客  QQ:1033553122   测试环境 nginx-1.10.0 负载均衡原理 客户端向反向代理发送请求,接着反向代理根据某种负载机制 ...

  5. HA主备路由模式的原理 + HA和负载均衡的区别

       HA主备路由模式的原理 HA是High Availability缩写,即高可用性 ,可防止网络中由于单个防火墙的设备故障或网络故障导致网络中断,保证网络服务的连续性和安全强度.目前,ha功能已经 ...

  6. springcloud ribbon的 @LoadBalanced注解

    在使用springcloud ribbon客户端负载均衡的时候,可以给RestTemplate bean 加一个@LoadBalanced注解,就能让这个RestTemplate在请求时拥有客户端负载 ...

  7. Spring cloud 之Ribbon(二)负载均衡原理

    ribbon实现负载均衡的原理 我们从Ribbon实现负载均衡的代码可以看到,Ribbon是通过RestTemPlate实现客户端负载均衡的,准确的说是RestTemPlate上的@LoadBalan ...

  8. SpringCloud学习笔记(7)----Spring Cloud Netflix之负载均衡-Ribbon的深入理解

    1. 注解@LoadBalanced 作用:识别应用名称,并进行负载均衡. 2. 入口类:LoadBalancerAutoConfiguration 说明:类头上的注解可以知道Ribbon 实现的负载 ...

  9. F5负载均衡原理

    一. 负载均衡技术 负载均衡技术在现有网络结构之上提供了一种廉价.有效.透明的方法,来扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 1.负载均衡发生的流程图 ...

随机推荐

  1. 全面系统Python3入门+进阶课程 ✌✌

    全面系统Python3入门+进阶课程 (一个人学习或许会很枯燥,但是寻找更多志同道合的朋友一起,学习将会变得更加有意义✌✌) 无论是大数据.人工智能还是机器学习,Python都是最热门的首选语言 ,这 ...

  2. Django-debug-toolbar(调试使用)

    Django-debug-toolbar django-debug-toolbar 是一组可配置的面板,可显示有关当前请求/响应的各种调试信息,并在单击时显示有关面板内容的更多详细信息. https: ...

  3. 「看完不后悔系列!」Maya的建模小技巧

    Maya 将最大的联合影响力降至最低 最大的联合影响力是游戏角色装备的已知要求. 但是,对于每种类型的生产来说,这实际上都是一个很好的工作流程. 从透视图上看,如果你将联合影响力从4更改为5,则不一定 ...

  4. SQLMAP SSI注入错误解决

    记一次SQL注入 目标地址:https://www.xxxx.com/ 之前补天提交过这个注入  后来貌似”修复了”(实际就是装了安全狗和过滤了一些关键字) 不过今天试了下 还是可以注入 可以看到已经 ...

  5. HDU 3371 Connect the Cities(并查集+Kruskal)

    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=3371 思路: 这道题很明显是一道最小生成树的题目,有点意思的是,它事先已经让几个点联通了.正是因为它先 ...

  6. Uipath 获取当前浏览器页面URL

    文章来源东京IT青年前线 http://www.rpatokyo.com   Uipath 获取当前浏览器页面URL的方法 Inject Js Script   因为目前没有直接获取页面URL的Act ...

  7. CSP考场Emacs使用指南[原创]

    前言: 据说,CSP考试,之后不再支持windows了呢. windows用户真得劲! 那用什么系统? Ubuntu上场了 Ubuntu编译指南 进入Ubuntu系统,在你想存的文件夹中新建一个空白文 ...

  8. vue系列---响应式原理实现及Observer源码解析(一)

    _ 阅读目录 一. 什么是响应式? 二:如何侦测数据的变化? 2.1 Object.defineProperty() 侦测对象属性值变化 2.2 如何侦测数组的索引值的变化 2.3 如何监听数组内容的 ...

  9. Java11新特性 - 新加一些实用的API

    1. 新的本机不可修改集合API 自从Java9开始,JDK里面为集合(List/Set/Map)都添加了of和copyOf方法,他们可以来创建不可变的集合. Question1:什么叫做不可变集合? ...

  10. .NET Framework概述

    1.NET Framework是为其运行的应用程序提供各种服务的托管执行环境,它包括两个主要组件:(1).公共语言运行时 (CLR),(2)..NET Framework 类库: 2.NET Fram ...