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. R语言学习 第八篇:常用的数据处理函数

    Basic包是R语言预装的开发包,包含了常用的数据处理函数,可以对数据进行简单地清理和转换,也可以在使用其他转换函数之前,对数据进行预处理,必须熟练掌握常用的数据处理函数,本文分享在数据处理时,经常使 ...

  2. 世界上最好的语言搭建短链接及统计功能(附API代码)

    前言 在这个营销的时代,短链接和二维码是企业进行营销中非常重要的工具,不仅仅是缩短了链接,而且还可以通过扩展获得更多的数据,诸如点击数.下载量.来源以及时间等等. 网上搜寻了一下比较有名有U.NU和0 ...

  3. Servlet的监听器

    Listener是Servlet的监听器,它可以监听客户端的请求.服务端的操作等.通过监听器,可以自动激发一些操作,比如监听在线的用户的数量.当增加一个HttpSession时,就激发sessionC ...

  4. mybatis学习日记-day01

    Mybatis说明: MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的 ...

  5. Mycat 分片规则详解--枚举分片

    实现方式:切分规则根据文件(partition-hash-int.txt)配置的可能的枚举来进行分片,此种分片规则理解为枚举分区,会比较适合于取值固定的场合,比如说省份(固定值) 优点:适用于按照省份 ...

  6. 研华ADAM 6000系列型号枚举值

    public enum Adam6000Type    {        Non = 0,        Adam6015 = 6015,        Adam6017 = 6017,        ...

  7. javascript里的循环语句

    前序:我一直对于for跟for..in存在一种误解,我觉得for都能把事情都做了,为啥还要for...in...这玩意了,有啥用,所以今天就说说JavaScript里的循环语句. 循环 要计算1+2+ ...

  8. tomcat启动时间过长的问题

    阿里云下的服务器安装jdk1.8和tomcat之后出现了一个问题,初次运行tomcat没有问题,可以正常访问tomcat首页,但是关闭之后再重启就发现tomcat首页刷不出来.而且再次关闭之后还报错了 ...

  9. 03-第一个脚本程序以及输入输出_Python编程之路

    上节课已经教大家安装了Python的解释器,那么这节课我们就可以正式来写代码了 说明:在下面的代码演示中,我将大部分使用python交互器演示代码的输入输出,注意">>>& ...

  10. W班-项目选题报告成绩

    作业链接 https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1715W/homework/907 作业要求 1份团队选题报告(word电 ...