程序员首页投稿(暂停使用,暂停投稿)

Netflix Ribbon的阅读理解

2016-12-30  本文已影响0人  化简为繁

最近用到Ribbon,总是觉得Ribbon既强大但是又不好用,其实根源还是对其内部的工作原理不够了解,导致对一些现象不能给出合理的解释,也影响了功能扩展。希望通过本次梳理,能够对Ribbon有一个较为清晰的理解!最近记性也不好了,还是要写下来才有印象。。。-_-

Ribbon + Spring Cloud

Ribbon是Netflix开源的一款用于客户端软负载均衡的工具软件。
Spring Cloud对Ribbon进行了一些封装以更好的使用Spring Boot的自动化配置理念。

先建个环境跑起来

<dependency>    
   <groupId>org.springframework.cloud</groupId>  
   <artifactId>spring-cloud-starter-zuul</artifactId>   
   <version>1.2.3.RELEASE</version>
</dependency>
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
    public static void main(String[] args) {    
        SpringApplication.run(ZuulApplication.class, args);
    }
}
server:  
    port: 7777
zuul:  
    routes:   
       node:
           path: /api/**
           serviceId: node
ribbon: 
   eureka:
      enabled: false
node: 
    ribbon:
      listOfServers: http://localhost:9600,http://localhost:9500

OK,访问http://localhost:7777/api/hello,就可以看到请求在9500和9600间不停切换了。

我在9500,9600启动了两个node express server, 只接受'/hello'请求,返回'Hello,world! {port}'

看看源码

如上,Ribbon发挥了负载均衡的作用,从结果来看,目前ribbon是使用轮询的方式进行负载均衡。为了更好的理解,还是看看代码,他到底怎么工作的?

入口

查看spring-cloud-netflix-core-1.2.3.RELEASE.jar/META-INF/spring.fatories文件:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration,
...
org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration,\

很明显,RibbonAutoConfiguration就是Spring Boot启动Rabbion的入口配置类。

RibbonAutoConfiguration

public class RibbonAutoConfiguration {
...
 @Bean
 public SpringClientFactory springClientFactory() {   
     SpringClientFactory   factory = new SpringClientFactory();  
     factory.setConfigurations(this.configurations);   return factory;}
...
}

很明显,最重要的bean就是SpringClientFactory, 为啥?因为其他bean都需要他去初始化。。。

SpringClientFactory

方法列表如图:


SpringClientFactory.png

查看方法列表,此类提供了获取指定serviceId的IClient, ILoadBalance, ILoadBalanceContext等对象的重要方法。

仔细查看获取LB(LoadBalance)实例的方法,发现LB实例最终从父类NamedContextFactory获取Bean。
Bean来源AnnotationConfigApplicationContext context ,

public <T> Map<String, T> getInstances(String name, Class<T> type) {
   AnnotationConfigApplicationContext context = getContext(name);   
    if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0) {    
      return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);   
    }   
    return null;
}

这个Context从那里获取我想要的bean实例呢?还是截图吧,这个鬼排版傻死了。

createContext

看看context的创建过程,上面的红圈处,它会尝试为每个serviceId使用属于自己的配置类(当然前提是你有对应的配置),并注册;
下面的红圈说明,它会注册一个默认的配置类this.defaultConfigType,

this.defaultConfigType = RibbonClientConfiguration.class;
context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);

至此,一个关键的配置类被发现了:RibbonClientConfiguration, 不容易-_-!

RibbonClientConfiguration

方法列表:


Paste_Image.png

基本上看着方法名就知道各种Bean是干什么的吧(IRule,IPing,ServerList,ILoadBalancer,ServerListFilter,RibbonLoadBalancerContext,RetryHandler,ServerIntrospector)。
更重要的是:我们可以大胆的为每个serviceId指定自己的配置类了,如下,为"node"指定IPing的特殊的实现类:

@RibbonClient(name = "node", configuration = NodeServiceConfig.class)
public class ZuulApplication {
...
}
public class NodeServiceConfig {  
  private String name = "node";   
  @Autowired    
  private IClientConfig iClientConfig;   
  @Bean    
  public IPing ribbonPing(IClientConfig iClientConfig) {    
      if (this.propertiesFactory.isSet(IPing.class, name)) {            
          return this.propertiesFactory.get(IPing.class, iClientConfig, name);       
       }        
      return new NoOpPing();   
   }
}

未完待续...

上一篇下一篇

猜你喜欢

热点阅读