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. JavaScript编码规范(2)

    变量 [强制] 变量.函数在使用前必须先定义. // good var name = 'MyName'; // bad name = 'MyName'; [强制] 每个 var 只能声明一个变量. 解 ...

  2. 【前端】input radio多选事件获取所有选中的id,radio样式优化可修改

    $("#all_button").on('click', function() { obj = document.getElementsByClassName("inpu ...

  3. 使用kafka connect,将数据批量写到hdfs完整过程

    版权声明:本文为博主原创文章,未经博主允许不得转载 本文是基于hadoop 2.7.1,以及kafka 0.11.0.0.kafka-connect是以单节点模式运行,即standalone. 首先, ...

  4. Javascript实现继承

    以下转自阮一峰的文章:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.h ...

  5. 百度API地图的标注不居中显示,而显示在左上角

    前言:今天弄个百度地图,弄了半天就是不居中,之前使用一直没有遇到这个问题.所以就一直在找原因. 百度地图对地图所在的div做了显示隐藏之类操作,标注就不再居中显示,而显示在左上角. 查了很久,有人提出 ...

  6. 【XML】 XML格式一些记录

    XML XML格式常用于网络通讯,本身不会有作为而是作为纯文本传输,可以说它是一种独立于应用和硬件的数据传输工具.虽然看起来XML比HTML要更加简单,也知道的更加晚一点,但是需要知道的是,XML才是 ...

  7. Java多线程:ThreadLocal

    一.ThreadLocal基础知识 ThreadLocal是线程的一个本地化对象,或者说是局部变量.当工作于多线程中的对象使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的 ...

  8. 基于hi-nginx的web开发(python篇)——cookie和会话管理

    hi-nginx通过redis管理会话. 要开启管理,需要做三件事. 第一件开启userid: userid on; userid_name SESSIONID; userid_domain loca ...

  9. 定位bug的姿势对吗?

    举个例子来说明 WEB页面上数据显示错误,本来应该显示38,  结果显示35,这个时候你怎么去定位这个问题出在哪里? 1.通过fiddler抓包工具(或者其他抓包工具), 分析接口返回的数据是35还是 ...

  10. u3d材质Tiling和Offset意义以及TRANSFORM_TEX

    1. TRANSFORM_TEX主要作用是拿顶点的uv去和材质球的tiling和offset作运算, 确保材质球里的缩放和偏移设置是正确的 下面这两个函数是等价的.o.uv =   TRANSFORM ...