ribbon 详解

1. 顶层架构

2. 简单的示例:使用ResourceTemplate方式

@Test
public void testGroup(){
HttpResourceGroup httpResourceGroup = Ribbon.createHttpResourceGroup("test",
ClientOptions.create().withMaxAutoRetries(3).
withConfigurationBasedServerList("localhost:8081,localhost:8080"));
HttpRequestTemplate<ByteBuf> recommendationsByUserIdTemplate = httpResourceGroup.newTemplateBuilder("recommendationsByUserId", ByteBuf.class)
.withMethod("GET")
.withUriTemplate("/aa/index")
.withHeader("X-Auth-Token", "abc")
//.withFallbackProvider(new RecommendationServiceFallbackHandler())
//.withResponseValidator(new RecommendationServiceResponseValidator())
.build(); RibbonRequest<ByteBuf> request = recommendationsByUserIdTemplate.requestBuilder()
.withRequestProperty("userId", "test")
.build();
ByteBuf buf = request.execute();
byte[] bytes = new byte[buf.capacity()];
buf.readBytes(bytes);
System.out.println(new String(bytes));
}

3.实现:

3.1 关键对象
public interface RibbonRequest<T> {

    /**
* Blocking API that returns a single (or last element if there is a sequence of objects from the execution) element
*/
public T execute(); /**
* Non blocking API that returns a {@link Future}, where its {@link Future#get()} method is blocking and returns a
* single (or last element if there is a sequence of objects from the execution) element
*/
public Future<T> queue(); /**
* Non blocking API that returns an {@link Observable} while the execution is started asynchronously.
* Subscribing to the returned {@link Observable} is guaranteed to get the complete sequence from
* the beginning, which might be replayed by the framework. Use this API for "fire and forget".
*/
public Observable<T> observe(); /**
* Non blocking API that returns an Observable. The execution is not started until the returned Observable is subscribed to.
*/
public Observable<T> toObservable(); /**
* Create a decorated {@link RequestWithMetaData} where you can call its similar blocking or non blocking
* APIs to get {@link RibbonResponse}, which in turn contains returned object(s) and
* some meta data from Hystrix execution.
*/
public RequestWithMetaData<T> withMetadata();
}

明显,最终生成的关键对象RibbonRequest,使用的时观察者模式,底层实现肯定会使用RxJava或者Hystrix。

3.2 关键实现:HystrixObservableCommandChain
HystrixObservableCommandChain<T> createHystrixCommandChain() {
List<HystrixObservableCommand<T>> commands = new ArrayList<HystrixObservableCommand<T>>(2);
if (cacheProvider != null) {
commands.add(new CacheObservableCommand<T>(cacheProvider.getCacheProvider(), cacheProvider.getKey(), cacheHystrixCacheKey,
requestProperties, template.cacheHystrixProperties()));
}
commands.add(new HttpResourceObservableCommand<T>(client, httpRequest, hystrixCacheKey, requestProperties, template.fallbackHandler(),
template.responseValidator(), template.getClassType(), template.hystrixProperties())); return new HystrixObservableCommandChain<T>(commands);
}

在HystrixObservableCommandChain执行toObservable的时候,会依次便利集合中所有的HystrixObservableCommand,知道其toObservable不为null。

所以,如果cacheProvider不为null会调用CacheObservableCommand的toObservable,如果cacheProvider为null,则直接调用HttpResourceObservableCommand的toObservable.

3.3 http请求:
Observable<HttpClientResponse<ByteBuf>> httpResponseObservable = httpClient.submit(httpRequest);
Observable<T> o =
(server == null ? selectServer() : Observable.just(server))
.concatMap(new Func1<Server, Observable<T>>() {
@Override
// Called for each server being selected
public Observable<T> call(Server server) {
context.setServer(server);
final ServerStats stats = loadBalancerContext.getServerStats(server); // Called for each attempt and retry
Observable<T> o = Observable
.just(server)
.concatMap(new Func1<Server, Observable<T>>() {
...
}); if (maxRetrysSame > 0)
o = o.retry(retryPolicy(maxRetrysSame, true));
return o;
}
}
if (maxRetrysSame > 0)
o = o.retry(retryPolicy(maxRetrysSame, true));
return o;

会调用统一服务器n次,后调用下一个服务器m次(n,m为设定的最大调用次数)。

4.简单示例:使用注解方式

public interface AAIndex {
@Http( method = Http.HttpMethod.GET,
uri = "http://localhost:8080/aa/index")
RibbonRequest<ByteBuf> index();
}
@Test
public void testRibbonAnnotation(){
AAIndex aaIndex = Ribbon.from(AAIndex.class);
ByteBuf buf = aaIndex.index().execute();
byte[] bytes = new byte[buf.capacity()];
buf.readBytes(bytes);
System.out.println(new String(bytes));
}

5.实现:

5.1 动态代理:
return (T) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{clientInterface, ProxyLifeCycle.class},
new RibbonDynamicProxy<T>(clientInterface, resourceGroupFactory, configFactory, transportFactory, processors)
);

使用JDK自带的代理类实现,代理了client接口,和ProxyLifeCycle,其实现具体类为RibbonDynamicProxy。

5.2 支持的注解:
static void registerAnnotationProcessors(AnnotationProcessorsProvider processors) {
processors.register(new HttpAnnotationProcessor());
processors.register(new HystrixAnnotationProcessor());
processors.register(new CacheProviderAnnotationProcessor());
processors.register(new ClientPropertiesProcessor());
}

最终的实现跟非注解方式的实现是一致的。

@SuppressWarnings("unchecked")
public <O> RibbonRequest<O> executeFromTemplate(Object[] args) {
HttpRequestBuilder<?> requestBuilder = httpRequestTemplateBuilder.build().requestBuilder();
withParameters(requestBuilder, args);
withContent(requestBuilder, args);
return (RibbonRequest<O>) requestBuilder.build();
}

ribbon 详解的更多相关文章

  1. Ribbon详解

    转自Ribbon详解 简介 ​ Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现.通过Spring Cloud的封装,可以让 ...

  2. Spring Cloud:使用Ribbon实现负载均衡详解(下)

    在上一篇文章(Spring Cloud:使用Ribbon实现负载均衡详解(上))中,我对 Ribbon 做了一个介绍,Ribbon 可以实现直接通过服务名称对服务进行访问.这一篇文章我详细分析一下如何 ...

  3. VC++ 2010 创建高级Ribbon界面详解(1)

    运用 VC++ 2010 创建高级 Ribbon 界面详解,包括 Ribbon 界面的结构层次.Ribbon 控件的使用等,ribbon 用户界面,ribbon interface ,ribbon 高 ...

  4. (2-3)Eureka详解

    基础架构 服务注册中心 服务提供者 服务消费者 服务治理 服务提供者 服务注册.在服务注册时,需要确认一下eureka.client.registerwith-eurek=ture参数是否正确,默认是 ...

  5. Spring Cloud Zuul 限流详解(附源码)(转)

    在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud中如何实现限流. 在 Zuul 上实现限流是个不错的选择,只需要编写一个过滤器就可以了,关键在于如何实现限流的算法. ...

  6. Zuul之Filter详解

    Zuul详解 官方文档:https://github.com/Netflix/zuul/wiki/How-it-Works Zuul的中心是一系列过滤器,能够在HTTP请求和响应的路由过程中执行一系列 ...

  7. Spring Cloud限流详解

    转自:https://blog.csdn.net/tracy38/article/details/78685707 在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud ...

  8. springcloud中Feign配置详解

    Spring Cloud中Feign配置详解 到目前为止,小伙伴们对Feign的使用已经掌握的差不多了,我们在前文也提到Feign是对Ribbon和Hystrix的整合,那么在Feign中,我们要如何 ...

  9. Spring Cloud(十二):Spring Cloud Zuul 限流详解(附源码)(转)

    前面已经介绍了很多zuul的功能,本篇继续介绍它的另一大功能.在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud中如何实现限流. 在 Zuul 上实现限流是个不错的选 ...

随机推荐

  1. 常用JS小知识汇总

    1 上传图片:html代码 <input id="image" type='file' name='myFile' size='15' onchange="show ...

  2. 关于browser-sync(在多个设备上进行网页调试)的问题点总结

    最近在看响应式网站的开发视频,其中有一部分非常有用,就是在多个设备上进行网页调试,通过使用browser-sync来实现,具体的步骤可以参照官网(http://www.browsersync.cn/) ...

  3. 【OpenCV-Python:实现人脸、人眼、嘴巴识别】实战(一)

    AI时代的到来,手机上的APP开始应用人脸识别去完成事情,如iphoneX的人脸解锁,百度自动贩卖机的人脸识别系统进行支付,支付宝的人脸识别登录等,提高了使用软件的易用性,但也因为其便利性,在某些市面 ...

  4. FMDatabaseQueue 如何保证线程安全

    这篇文章原来在用 Github Pages 搭建的博客上,现在决定重新用回博客园,所以把文章搬回来. FMDB 是 OC 针对 sqlite 的封装.在其文档的线程安全部分这样讲:同时从多个线程使用同 ...

  5. JS基础二

    JS的实现: 核心:ECMAScript ECMAScript 并不与任何具体浏览器相绑定,实际上,它也没有提到用于任何用户输入输出的方法(这点与 C 这类语言不同,它需要依赖外部的库来完成这类任务) ...

  6. JavaSE中常见的工具类

    Arrays 用来操作数组, 常用方法是 sort()和toString()方法 Iterator 我们常说的迭代器就是这哥们,专门用来操作集合元素的工具类 常用方法是: hasNex()t和next ...

  7. 笔记:JDBC 数据库

    数据库 URL 在连接数据库时,我们必须使用各种与数据库类型相关的参数,例如主机名.端口号和数据库名称等,JDBC使用了一种与普通URL相类似的语法来描述数据库,JDBC URL 一般语法为: jdb ...

  8. express+mongodb+socket.io

    node后端代码 // Setup basic express server var express = require('express'); var app = express(); var pa ...

  9. AndroidStudio R 文件标红

    一种不常见的问题 AndroidStudio 文件大小会有一定的限制,超过一定大小将无法解析.大型的Android项目容易出现这个问题. 可以按照下面的步骤解决这个问题: 在AndroidStudio ...

  10. Webpack执行命令参数详解

    一.概述前面的章节我们讲解了webpack的安装.webpack.config.js的 基本配置.webpack执行命名以及require方法的使用,不 知道大家有没有发现,当我们每次修改或者新增一个 ...