Ribbon踩坑后看源码

Ribbon使用和源码解析

    • 前言
  • Ribbon的使用
    • maven依赖
    • 代码使用
    • 更多配置
  • 源码分析
    • 源码入口
    • 主要配置类
    • 初始化相关
    • 服务调用过程
      • 负载均衡器LoadBanlance
      • 负载均衡策略IRule
      • 调用流程

前言

自定义了一个负载均衡策略,发现一个问题,服务a先调用服务b再调用服务c后,之后再调b服务404,简单的debug后发现再调b服务的时候loadbalancer里面的IRule已经变成了服务c的IRule,感觉是c服务初始化的时候把b服务的IRule覆盖了,百思不得其解。于是跟踪源码,发现了两个之前想不明白的问题,一个是LoadBalancer有IRule属性,IRule里又有LoadBalancer属性,负载均衡策略选择服务是使用的IRule里的LoadBalancer,二是每个被调用服务第一次被调用的时候会初始化一个子上下文,加载自己的bean。

之前通过在配置文件里面new IRule()定义策略,等于在父上下文里创建了单例bean,因为@ConditionalOnMissingBean注解,服务子上下文初始化的时候不会再次创建bean,所以多个服务的情况下会共用一个IRule,每次被调用服务初始化LoadBalancer都会把IRule设置成自己的,导致其他服务出现问题。

下面会通过对ribbon配置类、初始化、调用过程的源码追踪,大概的解析下ribbon的使用过程

Ribbon的使用

Ribbon是springcloud提供的一个客户端负载均衡器,和RestTemplate配合使用,通过拦截器对rest请求做一个拦截处理,获取可用服务列表,根据策略选择服务调用。

maven依赖

	
	<dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    
	<dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-ribbonartifactId>
        <version>${spring-cloud-netflix.version}version>
    dependency>

代码使用

	@LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

	@Autowired
    private final RestTemplate restTemplate;

	//分别调用服务service-b和服务service-c的service接口
    @RequestMapping(value = "/service", method = RequestMethod.GET)
    public String service() {
        String b = restTemplate.getForObject("http://service-b/service", String.class);
        String c = restTemplate.getForObject("http://service-c/service", String.class);
        return b + ";" + c;
    }

更多配置

源码分析

源码入口

通过springboot的spi启动配置类

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

主要配置类

org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration
此类通过spi在项目启动时加载,会初始化很多重要bean

@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
@AutoConfigureBefore({ LoadBalancerAutoConfiguration.class,//之后加载loadBalancer的配置
		AsyncLoadBalancerAutoConfiguration.class })
public class RibbonAutoConfiguration {

	@Autowired(required = false)
	private List<RibbonClientSpecification> configurations = new ArrayList<>();

	@Autowired
	private RibbonEagerLoadProperties ribbonEagerLoadProperties;//饥饿加载配置

	@Bean
	public HasFeatures ribbonFeature() {
		return HasFeatures.namedFeature("Ribbon", Ribbon.class);
	}

	//spring创建loadbalancer和clientConfig的工厂
	@Bean
	public SpringClientFactory springClientFactory() {
		SpringClientFactory factory = new SpringClientFactory();
		factory.setConfigurations(this.configurations);
		return factory;
	}

	//创建ribbon负载均衡选择的客户端
	@Bean
	@ConditionalOnMissingBean(LoadBalancerClient.class)
	public LoadBalancerClient loadBalancerClient() {
		return new RibbonLoadBalancerClient(springClientFactory());
	}

	//创建RibbonLoadBalanced重试工厂
	@Bean
	@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
	@ConditionalOnMissingBean
	public LoadBalancedRetryFactory loadBalancedRetryPolicyFactory(
			final SpringClientFactory clientFactory) {
		return new RibbonLoadBalancedRetryFactory(clientFactory);
	}

	//创建配置工厂
	@Bean
	@ConditionalOnMissingBean
	public PropertiesFactory propertiesFactory() {
		return new PropertiesFactory();
	}

	//饥饿加载初始化
	//ribbon默认是在调用服务的时候初始化,此配置可以设置服务在启动时初始化
	@Bean
	@ConditionalOnProperty("ribbon.eager-load.enabled")
	public RibbonApplicationContextInitializer ribbonApplicationContextInitializer() {
		return new RibbonApplicationContextInitializer(springClientFactory(),
				ribbonEagerLoadProperties.getClients());
	}

org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration
在RibbonAutoConfiguration之后加载,设置ClientHttpRequestInterceptor拦截器到restTemplate

@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

	@LoadBalanced
	@Autowired(required = false)
	private List<RestTemplate> restTemplates = Collections.emptyList();

	@Autowired(required = false)
	private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();

	@Bean
	@ConditionalOnMissingBean
	public LoadBalancerRequestFactory loadBalancerRequestFactory(
			LoadBalancerClient loadBalancerClient) {
		return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
	}

	@Configuration
	@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
	static class LoadBalancerInterceptorConfig {

		@Bean
		public LoadBalancerInterceptor ribbonInterceptor(
				LoadBalancerClient loadBalancerClient,
				LoadBalancerRequestFactory requestFactory) {
			//创建拦截器
			return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
		}

		@Bean
		@ConditionalOnMissingBean
		public RestTemplateCustomizer restTemplateCustomizer(
				final LoadBalancerInterceptor loadBalancerInterceptor) {
			return restTemplate -> {
				List<ClientHttpRequestInterceptor> list = new ArrayList<>(
						restTemplate.getInterceptors());
				list.add(loadBalancerInterceptor);
				//设置拦截器
				restTemplate.setInterceptors(list);
			};
		}

	}

初始化相关

org.springframework.cloud.netflix.ribbon.PropertiesFactory
属性工厂,ILoadBalancer、IRule等设置了映射字符串,这些类的对象通过get()方法创建,通过环境变量中配置serviceName.ribbon.NFLoadBalancerClassName可以指定调用服务的配置。get()在RibbonClientConfiguration通过@Bean注解创建bean对象时被调用

public class PropertiesFactory {

	@Autowired
	private Environment environment;

	private Map<Class, String> classToProperty = new HashMap<>();

	public PropertiesFactory() {
		classToProperty.put(ILoadBalancer.class, "NFLoadBalancerClassName");
		classToProperty.put(IPing.class, "NFLoadBalancerPingClassName");
		classToProperty.put(IRule.class, "NFLoadBalancerRuleClassName");
		classToProperty.put(ServerList.class, "NIWSServerListClassName");
		classToProperty.put(ServerListFilter.class, "NIWSServerListFilterClassName");
	}

	public boolean isSet(Class clazz, String name) {
		return StringUtils.hasText(getClassName(clazz, name));
	}
	//在环境变量里找到配置的类名
	public String getClassName(Class clazz, String name) {
		if (this.classToProperty.containsKey(clazz)) {
			String classNameProperty = this.classToProperty.get(clazz);
			String className = environment
					.getProperty(name + "." + NAMESPACE + "." + classNameProperty);
			return className;
		}
		return null;
	}
	//调用SpringClientFactory根据className创建对象
	@SuppressWarnings("unchecked")
	public <C> C get(Class<C> clazz, IClientConfig config, String name) {
		String className = getClassName(clazz, name);
		if (StringUtils.hasText(className)) {
			try {
				Class<?> toInstantiate = Class.forName(className);
				return (C) SpringClientFactory.instantiateWithConfig(toInstantiate,
						config);
			}
			catch (ClassNotFoundException e) {
				throw new IllegalArgumentException("Unknown class to load " + className
						+ " for class " + clazz + " named " + name);
			}
		}
		return null;
	}

}

org.springframework.cloud.context.named.NamedContextFactory
此类是springCloud提供的一个非常重要的工厂类,通常在spring项目中,只有一个springApplicationContext,但是在微服务体系中,一个服务中会调用多个服务,每个被调用服务都有自己的ApplicationContext,它们的父context为当前服务的context。获取bean不再是context.getBean(classType),而是context.getInstanse(serviceName,classType)。ribbon配置类加载SpringClientFactory时会调用构造方法,config为RibbonClientConfiguration类

public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
		implements DisposableBean, ApplicationContextAware {

	private final String propertySourceName;

	private final String propertyName;

	//被调用服务的spring上下文
	private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();

	private Map<String, C> configurations = new ConcurrentHashMap<>();

	private ApplicationContext parent;

	private Class<?> defaultConfigType;

	//构造器,子类SpringClientFactory创建的时候调用,defaultConfigType为RibbonClientConfiguration
	public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName,
			String propertyName) {
		this.defaultConfigType = defaultConfigType;
		this.propertySourceName = propertySourceName;
		this.propertyName = propertyName;
	}

	@Override
	public void setApplicationContext(ApplicationContext parent) throws BeansException {
		this.parent = parent;//通过ApplicationContextAware得到父context并设置
	}
	
	public void setConfigurations(List<C> configurations) {
		for (C client : configurations) {//设置被调用服务的configuration
			this.configurations.put(client.getName(), client);
		}
	}

	@Override
	public void destroy() {//遍历销毁
		Collection<AnnotationConfigApplicationContext> values = this.contexts.values();
		for (AnnotationConfigApplicationContext context : values) {
			context.close();
		}
		this.contexts.clear();
	}

	protected AnnotationConfigApplicationContext getContext(String name) {
		if (!this.contexts.containsKey(name)) {
			synchronized (this.contexts) {
				if (!this.contexts.containsKey(name)) {
					this.contexts.put(name, createContext(name));//为空则创建
				}
			}
		}
		return this.contexts.get(name);
	}

	protected AnnotationConfigApplicationContext createContext(String name) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		if (this.configurations.containsKey(name)) {//注册配置类
			for (Class<?> configuration : this.configurations.get(name)
					.getConfiguration()) {
				context.register(configuration);
			}
		}
		for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
			if (entry.getKey().startsWith("default.")) {
				for (Class<?> configuration : entry.getValue().getConfiguration()) {
					context.register(configuration);
				}
			}
		}
		context.register(PropertyPlaceholderAutoConfiguration.class,
				this.defaultConfigType);
		context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(
				this.propertySourceName,
				Collections.<String, Object>singletonMap(this.propertyName, name)));
		if (this.parent != null) {
			// Uses Environment from parent as well as beans
			context.setParent(this.parent);
			// jdk11 issue
			// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
			context.setClassLoader(this.parent.getClassLoader());
		}
		context.setDisplayName(generateDisplayName(name));
		context.refresh();//刷新context,初始化bean
		return context;
	}
	//从context中获取实例
	public <T> T getInstance(String name, Class<T> type) {
		AnnotationConfigApplicationContext context = getContext(name);
		if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
				type).length > 0) {
			return context.getBean(type);
		}
		return null;
	}

org.springframework.cloud.netflix.ribbon.SpringClientFactory
此类是基于NamedContextFactory封装的工厂类,用来获取ILoadBalancer和IClientConfig

public class SpringClientFactory extends NamedContextFactory<RibbonClientSpecification> {
	//固定值ribbon命名空间
	static final String NAMESPACE = "ribbon";

	public SpringClientFactory() {
		//调用父类NamedContextFactory构造器设置属性
		//设置配置类为RibbonClientConfiguration
		super(RibbonClientConfiguration.class, NAMESPACE, "ribbon.client.name");
	}
	/**
	 * 获取rest客户端,restTemplate拦截器设置请求时创建,用来远程调用服务接口
	 */
	public <C extends IClient<?, ?>> C getClient(String name, Class<C> clientClass) {
		return getInstance(name, clientClass);
	}

	/**
	 * 通过服务名获取负载均衡器实例,通过这个按策略选择服务调用,restTemplate拦截器设置请求时创建
	 */
	public ILoadBalancer getLoadBalancer(String name) {
		return getInstance(name, ILoadBalancer.class);
	}

	/**
	 * 获取rest客户端配置,restTemplate拦截器设置请求时创建,用来远程调用服务接口
	 */
	public IClientConfig getClientConfig(String name) {
		return getInstance(name, IClientConfig.class);
	}

	static <C> C instantiateWithConfig(Class<C> clazz, IClientConfig config) {
		return instantiateWithConfig(null, clazz, config);
	}

	/**
	 * 通过服务名和类型获取实例,每个服务都有自己的applicationContext
	 */
	@Override
	public <C> C getInstance(String name, Class<C> type) {
		C instance = super.getInstance(name, type);
		if (instance != null) {
			return instance;
		}
		IClientConfig config = getInstance(name, IClientConfig.class);
		return instantiateWithConfig(getContext(name), type, config);
	}

	/**
	 * 通过服务名获取自己的applicationContext
	 */
	@Override
	protected AnnotationConfigApplicationContext getContext(String name) {
		return super.getContext(name);
	}
}

org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration
每个被调用服务加载配置刷新上下文的时候调用,创建ribbon客户端的各个bean,会先通过PropertiesFactory找环境变量中的配置创建对应类型的组件bean,没有则调无参构造器创建

@Configuration
@EnableConfigurationProperties
@Import({ HttpClientConfiguration.class, OkHttpRibbonConfiguration.class,
		RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class })
public class RibbonClientConfiguration {

	/**
	 * Ribbon client default connect timeout.
	 */
	public static final int DEFAULT_CONNECT_TIMEOUT = 1000;

	/**
	 * Ribbon client default read timeout.
	 */
	public static final int DEFAULT_READ_TIMEOUT = 1000;

	/**
	 * Ribbon client default Gzip Payload flag.
	 */
	public static final boolean DEFAULT_GZIP_PAYLOAD = true;

	@RibbonClientName
	private String name = "client";

	// TODO: maybe re-instate autowired load balancers: identified by name they could be
	// associated with ribbon clients

	@Autowired
	private PropertiesFactory propertiesFactory;

	@Bean
	@ConditionalOnMissingBean
	public IClientConfig ribbonClientConfig() {
		DefaultClientConfigImpl config = new DefaultClientConfigImpl();
		config.loadProperties(this.name);
		config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);
		config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);
		config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);
		return config;
	}

	@Bean
	@ConditionalOnMissingBean
	public IRule ribbonRule(IClientConfig config) {
		//负载均衡策略
		if (this.propertiesFactory.isSet(IRule.class, name)) {
			return this.propertiesFactory.get(IRule.class, config, name);
		}
		//默认创建
		ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
		rule.initWithNiwsConfig(config);
		return rule;
	}

	@Bean
	@ConditionalOnMissingBean
	public IPing ribbonPing(IClientConfig config) {
		//负责检查服务是否存活
		if (this.propertiesFactory.isSet(IPing.class, name)) {
			return this.propertiesFactory.get(IPing.class, config, name);
		}
		return new DummyPing();
	}

	@Bean
	@ConditionalOnMissingBean
	@SuppressWarnings("unchecked")
	public ServerList<Server> ribbonServerList(IClientConfig config) {
		//调用服务列表
		if (this.propertiesFactory.isSet(ServerList.class, name)) {
			return this.propertiesFactory.get(ServerList.class, config, name);
		}
		ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
		serverList.initWithNiwsConfig(config);
		return serverList;
	}

	@Bean
	@ConditionalOnMissingBean
	public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
			ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
			IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
		//负载均衡器
		if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
			return this.propertiesFactory.get(ILoadBalancer.class, config, name);
		}
		return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
				serverListFilter, serverListUpdater);
	}

	@Bean
	@ConditionalOnMissingBean
	@SuppressWarnings("unchecked")
	public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
		//服务列表过滤器
		if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
			return this.propertiesFactory.get(ServerListFilter.class, config, name);
		}
		ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
		filter.initWithNiwsConfig(config);
		return filter;
	}

org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor
http拦截器,restTemplate请求的时候会执行ClientHttpRequestInterceptor的intercept方法,上述配置类会构造此拦截器并设置到restTemplate中

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {

	private LoadBalancerClient loadBalancer;

	private LoadBalancerRequestFactory requestFactory;

	public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
			LoadBalancerRequestFactory requestFactory) {
		this.loadBalancer = loadBalancer;
		this.requestFactory = requestFactory;
	}

	public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
		this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
	}

	@Override
	public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) throws IOException {
		final URI originalUri = request.getURI();//从request中解析到uri
		String serviceName = originalUri.getHost();//从uri中获取服务名
		Assert.state(serviceName != null,
				"Request URI does not contain a valid hostname: " + originalUri);
		return this.loadBalancer.execute(serviceName,//执行过滤器
				this.requestFactory.createRequest(request, body, execution)//创建请求);
	}

}

总结一下,初始化过程如下:

  1. 通过spi加载RibbonAutoConfiguration,创建bean对象SpringClientFactory(获取ribbon的loadBalancer和CilentConfig的工厂)、RibbonLoadBalancerClient(负责均衡客户端,继承LoadBalancerClient,主要有选择服务choose(serviceId)和执行请求execute(serviceId, LoadBalancerRequest request)方法)、PropertiesFactory(属性工厂,可以通过环境变量配置创建各被调用服务的组件)
  2. 加载LoadBalancerAutoConfiguration,创建LoadBalancerInterceptor拦截器,将上述配置的loadBalancerClient设置到里面,再将拦截器设置到restTemplate里面
  3. ribbon调用时,会从SpringClientFactory中获取需要的bean,开始不存在,首次加载时会创建被调用服务的子applicationContext,然后加载RibbonClientConfiguration时创建里面的各组件bean

服务调用过程

先介绍几个调用过程中的核心类

负载均衡器LoadBanlance

Ribbon踩坑后看源码_第1张图片
顶层接口ILoadBalancer提供了添加、选择、获取、标记下线服务的方法
Ribbon踩坑后看源码_第2张图片

通过RibbonClientConfiguration可知默认会使用ZoneAwareLoadBalancer,创建时会一级级的构造父类,其祖父类BaseLoadBalancer初始化的时候会设置Rule和Ping组件。

负载均衡策略IRule

Ribbon踩坑后看源码_第3张图片
顶层接口IRule提供了选择服务、设置和获取负载均衡器的方法
Ribbon踩坑后看源码_第4张图片
下面举例介绍下轮询的Rule

public class RoundRobinRule extends AbstractLoadBalancerRule {

    private AtomicInteger nextServerCyclicCounter;
    private static final boolean AVAILABLE_ONLY_SERVERS = true;
    private static final boolean ALL_SERVERS = false;

    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

    public RoundRobinRule() {
        nextServerCyclicCounter = new AtomicInteger(0);
    }

    public RoundRobinRule(ILoadBalancer lb) {
        this();
        setLoadBalancer(lb);//父类AbstractLoadBalancerRule设置属性lb
    }

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }

        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
            List<Server> reachableServers = lb.getReachableServers();//获取可用服务
            List<Server> allServers = lb.getAllServers();//获取所有服务
            int upCount = reachableServers.size();
            int serverCount = allServers.size();

            if ((upCount == 0) || (serverCount == 0)) {
                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

            int nextServerIndex = incrementAndGetModulo(serverCount);//关键轮询方法
            server = allServers.get(nextServerIndex);//获取服务

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }

            // Next.
            server = null;
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: "
                    + lb);
        }
        return server;
    }

    /**
     * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
     *
     * @param modulo The modulo to bound the value of the counter.
     * @return The next value.
     */
    private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextServerCyclicCounter.get();//得到当前index
            int next = (current + 1) % modulo;//加1后对服务总数取模
            if (nextServerCyclicCounter.compareAndSet(current, next))//通过cas更新当前index为下个服务,成功则返回,失败则开启下次循环
                return next;
        }
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

可见lb中有Irule属性,Irule有会存lb属性,最后调用的时候直接调用IRule的choose方法选择服务

调用流程

  1. 调用restTemplate.getForObject(“http://service-b/service”, String.class)进入restTemplate的doExecute方法,执行ClientHttpRequestInterceptor的intercept方法,进入LoadBalancerInterceptor的intercept方法
	public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) throws IOException {
		final URI originalUri = request.getURI();//获取uri
		String serviceName = originalUri.getHost();//获取服务名
		Assert.state(serviceName != null,
				"Request URI does not contain a valid hostname: " + originalUri);
		//执行请求
		return this.loadBalancer.execute(serviceName,
				//构造loadbalancerrequest
				this.requestFactory.createRequest(request, body, execution));
	}
  1. this.requestFactory.createRequest(request, body, execution)方法
    创建一个LoadBalancerRequest后续调用
public LoadBalancerRequest<ClientHttpResponse> createRequest(
			final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) {
		return instance -> {
			HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance,
					this.loadBalancer);
			if (this.transformers != null) {
				for (LoadBalancerRequestTransformer transformer : this.transformers) {
					serviceRequest = transformer.transformRequest(serviceRequest,
							instance);
				}
			}
			return execution.execute(serviceRequest, body);
		};
	}
  1. RibbonLoadBalancerClient执行execute方法,获取负载均衡器并选择服务执行调用,getLoadBalancer(serviceId)会调用SpringClientFactory.getLoadBalancer(serviceId),即前面讲到的getInstance,当被调用服务没有被调用过,会先初始化被调服务的context,再获取lb。getServer(loadBalancer, hint)会执行loadBalancer.chooseServer(),然后BaseLoadBalancer.chooseServer,最后调用this.rule.choose(key)选择服务器
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
			throws IOException {
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);//获取负载均衡器
		Server server = getServer(loadBalancer, hint);//选择服务
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}
		RibbonServer ribbonServer = new RibbonServer(serviceId, server,
				isSecure(server, serviceId),
				serverIntrospector(serviceId).getMetadata(server));

		return execute(serviceId, ribbonServer, request);//执行request请求返回结果
	}
  1. 执行execute方法,request.apply(serviceInstance)最终会调到第2步的execution.execute(serviceRequest, body)方法,返回最终结果
public <T> T execute(String serviceId, ServiceInstance serviceInstance,
			LoadBalancerRequest<T> request) throws IOException {
		Server server = null;
		if (serviceInstance instanceof RibbonServer) {
			server = ((RibbonServer) serviceInstance).getServer();
		}
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}

		RibbonLoadBalancerContext context = this.clientFactory
				.getLoadBalancerContext(serviceId);
		RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);

		try {
			T returnVal = request.apply(serviceInstance);
			statsRecorder.recordStats(returnVal);
			return returnVal;
		}
		// catch IOException and rethrow so RestTemplate behaves correctly
		catch (IOException ex) {
			statsRecorder.recordStats(ex);
			throw ex;
		}
		catch (Exception ex) {
			statsRecorder.recordStats(ex);
			ReflectionUtils.rethrowRuntimeException(ex);
		}
		return null;
	}

public class AsyncLoadBalancerInterceptor implements AsyncClientHttpRequestInterceptor {
    private LoadBalancerClient loadBalancer;

    public AsyncLoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
        this.loadBalancer = loadBalancer;
    }

    public ListenableFuture<ClientHttpResponse> intercept(final HttpRequest request, final byte[] body, final AsyncClientHttpRequestExecution execution) throws IOException {
        URI originalUri = request.getURI();
        String serviceName = originalUri.getHost();
        return (ListenableFuture)this.loadBalancer.execute(serviceName, new LoadBalancerRequest<ListenableFuture<ClientHttpResponse>>() {
        	//上面apply接口的实现,会执行上述第2步最后的执行
            public ListenableFuture<ClientHttpResponse> apply(final ServiceInstance instance) throws Exception {
                HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, AsyncLoadBalancerInterceptor.this.loadBalancer);
                return execution.executeAsync(serviceRequest, body);
            }
        });
    }
}

你可能感兴趣的:(java,spring,ribbon)