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. 学习ASP.NET Core Razor 编程系列二——添加一个实体

    在Razor页面应用程序中添加一个实体 在本篇文章中,学习添加用于管理数据库中的书籍的实体类.通过实体框架(EF Core)使用这些类来处理数据库.EF Core是一个对象关系映射(ORM)框架,它简 ...

  2. cesium Animation显示系统时间

    var d = new Date(); var hour = 0 - d.getTimezoneOffset(); viewer.animation.viewModel.timeFormatter = ...

  3. SSM 使用 mybatis 分页插件 pagehepler 实现分页

    使用分页插件的原因,简化了sql代码的写法,实现较好的物理分页,比写一段完整的分页sql代码,也能减少了误差性. Mybatis分页插件 demo 项目地址:https://gitee.com/fre ...

  4. PHP中的ArrayAccess用法详解

    在Laravel的源码当中,作者多次使用到了PHP SPL中的ArrayAccess接口,那么这个ArrayAccess接口到底有什么作用呢?我会用一个简单的例子跟大家说明. 请看下面的这段代码,Fo ...

  5. CI框架传递数组到view层问题记录

    给大家分享一下在做页面显示天气预报功能中遇到的问题和解决方法!! 项目开发中,我用的天气预报API是心知天气的免费接口.关于天气预报接口,可用的有很多,看需求怎么要求了!有兴趣的小伙伴可以链接到这个地 ...

  6. 笔记:Maven 依赖及配置详解

    dependencies 配置节,主要用于配置项目依赖的其他包,其子节点 dependency 用来配置具体依赖包,有groupId.artifactId.version.scope等子节点来说明,配 ...

  7. 【Python】 uuid生成唯一ID

    uuid uuid是128位的全局唯一标识符(univeral unique identifier),通常用32位的一个字符串的形式来表现.有时也称guid(global unique identif ...

  8. Frequent Value

    Frequent Value poj-3368 题目大意:给你n个数的数列,保证它是单调递增的.给你m个询问,每个询问是询问两个节点之间最长的连续的相等的数的长度. 注释:n,m<=100000 ...

  9. Java基础学习笔记二 Java基础语法

    注释 注释用来解释和说明程序的文字,注释是不会被执行的. 单行注释 //这是一条单行注释 public int i; 多行注释 /* 这是 * 一段注释, * 它跨越了多个行 */ public vo ...

  10. alpha冲刺第四天

    一.合照 二.项目燃尽图 三.项目进展 今天实现了登录界面和服务器的连接了,牵手成功. 一些具体的界面细化实现,一些button的响应实现 四.明日规划 登录界面和服务器的连接实现耗费了太多时间,接下 ...