Spring Cloud Ribbon的原理

直接开撸代码,通过代码来看Ribbon是如何实现的。

1:RibbonAutoConfiguration配置生成RibbonLoadBalancerClient实例。

代码位置:org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration

 1 @Configuration
 2 @Conditional({RibbonAutoConfiguration.RibbonClassesConditions.class})
 3 @RibbonClients
 4 @AutoConfigureAfter(
 5     name = {"org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"}
 6 )
 7 @AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
 8 @EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
 9 public class RibbonAutoConfiguration {
10     @Autowired(
11         required = false
12     )
13     private List<RibbonClientSpecification> configurations = new ArrayList();
14     @Autowired
15     private RibbonEagerLoadProperties ribbonEagerLoadProperties;
16 
17     //...略
18 
19     @Bean
20     @ConditionalOnMissingBean({LoadBalancerClient.class})
21     public LoadBalancerClient loadBalancerClient() {
22         return new RibbonLoadBalancerClient(this.springClientFactory());
23     }
24 
25     // ....略
26 
27 }    

先看配置条件项,RibbonAutoConfiguration配置必须在LoadBalancerAutoConfiguration配置前执行,因为在LoadBalancerAutoConfiguration配置中会使用RibbonLoadBalancerClient实例。
RibbonLoadBalancerClient继承自LoadBalancerClient接口,是负载均衡客户端,也是负载均衡策略的调用方。

2.LoadBalancerInterceptorConfig配置生成:
1).负载均衡拦截器LoadBalancerInterceptor实例
包含:
  LoadBalancerClient实现类的RibbonLoadBalancerClient实例
  负载均衡的请求创建工厂LoadBalancerRequestFactory:实例
2).RestTemplate自定义的RestTemplateCustomizer实例

代码位置:org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration

 1 @Configuration(proxyBeanMethods = false)
 2 @ConditionalOnClass(RestTemplate.class)
 3 @ConditionalOnBean(LoadBalancerClient.class)
 4 @EnableConfigurationProperties(LoadBalancerRetryProperties.class)
 5 public class LoadBalancerAutoConfiguration {
 6 
 7     @LoadBalanced
 8     @Autowired(required = false)
 9     private List<RestTemplate> restTemplates = Collections.emptyList();
10 
11     @Autowired(required = false)
12     private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
13 
14     @Bean
15     public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
16             final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
17         return () -> restTemplateCustomizers.ifAvailable(customizers -> {
18             for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
19                 for (RestTemplateCustomizer customizer : customizers) {
20                     customizer.customize(restTemplate);
21                 }
22             }
23         });
24     }
25 
26     @Bean
27     @ConditionalOnMissingBean
28     public LoadBalancerRequestFactory loadBalancerRequestFactory(
29             LoadBalancerClient loadBalancerClient) {
30         return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
31     }
32 
33     @Configuration(proxyBeanMethods = false)
34     @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
35     static class LoadBalancerInterceptorConfig {
36 
37         @Bean
38         public LoadBalancerInterceptor ribbonInterceptor(
39                 LoadBalancerClient loadBalancerClient,
40                 LoadBalancerRequestFactory requestFactory) {
41             return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
42         }
43 
44         @Bean
45         @ConditionalOnMissingBean
46         public RestTemplateCustomizer restTemplateCustomizer(
47                 final LoadBalancerInterceptor loadBalancerInterceptor) {
48             return restTemplate -> {
49                 List<ClientHttpRequestInterceptor> list = new ArrayList<>(
50                         restTemplate.getInterceptors());
51                 list.add(loadBalancerInterceptor);
52                 restTemplate.setInterceptors(list);
53             };
54         }
55 
56     }
57 
58         // .....略    
59 }
60 
61     

先看配置条件项:
要求在项目环境中必须要有RestTemplate类。
要求必须要有LoadBalancerClient接口的实现类的实例,也就是上一步生成的RibbonLoadBalancerClient。

3.通过上面一步创建的RestTemplateCustomizer配置所有RestTemplate实例,就是将负载均衡拦截器设置给RestTemplate实例。

 1 @Configuration(proxyBeanMethods = false)
 2 @ConditionalOnClass(RestTemplate.class)
 3 @ConditionalOnBean(LoadBalancerClient.class)
 4 @EnableConfigurationProperties(LoadBalancerRetryProperties.class)
 5 public class LoadBalancerAutoConfiguration {
 6 
 7     @LoadBalanced
 8     @Autowired(required = false)
 9     private List<RestTemplate> restTemplates = Collections.emptyList();
10 
11     @Autowired(required = false)
12     private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
13 
14     @Bean
15     public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
16             final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
17         return () -> restTemplateCustomizers.ifAvailable(customizers -> {
18             for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
19                 for (RestTemplateCustomizer customizer : customizers) {
20                     customizer.customize(restTemplate);
21                 }
22             }
23         });
24     }
25 
26     @Bean
27     @ConditionalOnMissingBean
28     public LoadBalancerRequestFactory loadBalancerRequestFactory(
29             LoadBalancerClient loadBalancerClient) {
30         return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
31     }
32 
33     @Configuration(proxyBeanMethods = false)
34     @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
35     static class LoadBalancerInterceptorConfig {
36 
37         @Bean
38         public LoadBalancerInterceptor ribbonInterceptor(
39                 LoadBalancerClient loadBalancerClient,
40                 LoadBalancerRequestFactory requestFactory) {
41             return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
42         }
43 
44         @Bean
45         @ConditionalOnMissingBean
46         public RestTemplateCustomizer restTemplateCustomizer(
47                 final LoadBalancerInterceptor loadBalancerInterceptor) {
48             return restTemplate -> {
49                 List<ClientHttpRequestInterceptor> list = new ArrayList<>(
50                         restTemplate.getInterceptors());
51                 list.add(loadBalancerInterceptor);
52                 restTemplate.setInterceptors(list);
53             };
54         }
55 
56     }
57 
58     // ...略
59 }

restTemplate.setInterceptors(list)这个地方就是注入负载均衡拦截器的地方LoadBalancerInterceptor。
从这个地方实际上也可以猜出来,RestTemplate可以通过注入的拦截器来构建相应的请求实现负载均衡。
也能看出来可以自定义拦截器实现其他目的。

 4.RibbonClientConfiguration配置生成ZoneAwareLoadBalancer实例

代码位置:org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration

 1 @Configuration(proxyBeanMethods = false)
 2 @EnableConfigurationProperties
 3 @Import({ HttpClientConfiguration.class, OkHttpRibbonConfiguration.class,
 4         RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class })
 5 public class RibbonClientConfiguration {
 6 
 7 
 8     // ...略
 9     
10     @Bean
11     @ConditionalOnMissingBean
12     public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
13             ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
14             IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
15         if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
16             return this.propertiesFactory.get(ILoadBalancer.class, config, name);
17         }
18         return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
19                 serverListFilter, serverListUpdater);
20     }
21     
22    // ...略
23 }

ZoneAwareLoadBalancer继承自ILoadBalancer接口,该接口有一个方法:

1     /**
2      * Choose a server from load balancer.
3      * 
4      * @param key An object that the load balancer may use to determine which server to return. null if 
5      *         the load balancer does not use this parameter.
6      * @return server chosen
7      */
8     public Server chooseServer(Object key);

ZoneAwareLoadBalancer就是一个具体的负载均衡实现类,也是默认的负载均衡类,通过对chooseServer方法的实现选取某个服务实例。

拦截&请求

 

1.使用RestTemplate进行Get、Post等各种请求,都是通过doExecute方法实现

代码位置:org.springframework.web.client.RestTemplate

 1 public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
 2 
 3     // ....略
14 @Nullable 15 protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, 16 @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException { 17 18 Assert.notNull(url, "URI is required"); 19 Assert.notNull(method, "HttpMethod is required"); 20 ClientHttpResponse response = null; 21 try { 22 ClientHttpRequest request = createRequest(url, method); 23 if (requestCallback != null) { 24 requestCallback.doWithRequest(request); 25 } 26 response = request.execute(); 27 handleResponse(url, method, response); 28 return (responseExtractor != null ? responseExtractor.extractData(response) : null); 29 }   30 catch (IOException ex) { 31 String resource = url.toString(); 32 String query = url.getRawQuery(); 33 resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource); 34 throw new ResourceAccessException("I/O error on " + method.name() + 35 " request for \"" + resource + "\": " + ex.getMessage(), ex); 36 } 37 finally { 38 if (response != null) { 39 response.close(); 40 } 41 } 42 } 43 44 }

可以看出来其实底层也是通过HTTP请求来进行实现的服务请求。

支持的各种http请求方法最终都是调用doExecute方法,该方法内调用创建方法创建请求实例,并执行请求得到响应对象。

2.生成请求实例创建工厂

上一步代码中,调用createRequest方法创建请求实例,这个方法是定义在父类中。
先整理出主要的继承关系:

 

createRequest方法实际是定义在HttpAccessor抽象类中。

 1 public abstract class HttpAccessor {
 2 
 3     // ...略
 4 
 5     protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
 6         ClientHttpRequest request = getRequestFactory().createRequest(url, method);
 7         initialize(request);
 8         if (logger.isDebugEnabled()) {
 9             logger.debug("HTTP " + method.name() + " " + url);
10         }
11         return request;
12     }
13 
14 }

在createRequest方法中调用getRequestFactory方法获得请求实例创建工厂,实际上getRequestFactory并不是当前HttpAccessor类中定义的,而是在子类InterceptingHttpAccessor中定义的。

 1 public abstract class InterceptingHttpAccessor extends HttpAccessor {
 2     
 3     // ...略
 4 
 5     @Override
 6     public ClientHttpRequestFactory getRequestFactory() {
 7         List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
 8         if (!CollectionUtils.isEmpty(interceptors)) {
 9             ClientHttpRequestFactory factory = this.interceptingRequestFactory;
10             if (factory == null) {
11                 factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
12                 this.interceptingRequestFactory = factory;
13             }
14             return factory;
15         }
16         else {
17             return super.getRequestFactory();
18         }
19     }
20 
21 }

在这里做了个小动作,首先还是通过HttpAccessor类创建并获得SimpleClientHttpRequestFactory工厂,这个工厂主要就是在没有拦截器的时候创建基本请求实例。

其次,在有拦截器注入的情况下,创建InterceptingClientHttpRequestFactory工厂,该工厂就是创建带拦截器的请求实例,因为注入了负载均衡拦截器,所以这里就从InterceptingClientHttpRequestFactory工厂创建。

3.通过工厂创建请求实例

创建实例就看工厂的createRequest方法。

 1 public class InterceptingClientHttpRequestFactory extends AbstractClientHttpRequestFactoryWrapper {
 2 
 3     private final List<ClientHttpRequestInterceptor> interceptors;
 4 
 5 
 6     /**
 7      * Create a new instance of the {@code InterceptingClientHttpRequestFactory} with the given parameters.
 8      * @param requestFactory the request factory to wrap
 9      * @param interceptors the interceptors that are to be applied (can be {@code null})
10      */
11     public InterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory,
12             @Nullable List<ClientHttpRequestInterceptor> interceptors) {
13 
14         super(requestFactory);
15         this.interceptors = (interceptors != null ? interceptors : Collections.emptyList());
16     }
17 
18 
19     @Override
20     protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {
21         return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
22     }
23 
24 }

就是new了个InterceptingClientHttpRequest实例,并且把拦截器、基本请求实例创建工厂注进去。

4.请求实例调用配置阶段注入的负载均衡拦截器的拦截方法intercept

可从第1步看出,创建完请求实例后,通过执行请求实例的execute方法执行请求。

1             ClientHttpRequest request = createRequest(url, method);
2             if (requestCallback != null) {
3                 requestCallback.doWithRequest(request);
4             }
5             response = request.execute();

实际请求实例是InterceptingClientHttpRequest,execute实际是在它的父类中。

类定义位置:org.springframework.http.client.InterceptingClientHttpRequest

看一下它们的继承关系。

 在execute方法中实际调用了子类实现的executeInternal方法。

 1 public abstract class AbstractClientHttpRequest implements ClientHttpRequest {
 2 
 3     private final HttpHeaders headers = new HttpHeaders();
 4 
 5     private boolean executed = false;
 6 
 7 
 8     @Override
 9     public final HttpHeaders getHeaders() {
10         return (this.executed ? HttpHeaders.readOnlyHttpHeaders(this.headers) : this.headers);
11     }
12 
13     @Override
14     public final OutputStream getBody() throws IOException {
15         assertNotExecuted();
16         return getBodyInternal(this.headers);
17     }
18 
19     @Override
20     public final ClientHttpResponse execute() throws IOException {
21         assertNotExecuted();
22         ClientHttpResponse result = executeInternal(this.headers);
23         this.executed = true;
24         return result;
25     }
26 
27     /**
28      * Assert that this request has not been {@linkplain #execute() executed} yet.
29      * @throws IllegalStateException if this request has been executed
30      */
31     protected void assertNotExecuted() {
32         Assert.state(!this.executed, "ClientHttpRequest already executed");
33     }
34 
35 
36     /**
37      * Abstract template method that returns the body.
38      * @param headers the HTTP headers
39      * @return the body output stream
40      */
41     protected abstract OutputStream getBodyInternal(HttpHeaders headers) throws IOException;
42 
43     /**
44      * Abstract template method that writes the given headers and content to the HTTP request.
45      * @param headers the HTTP headers
46      * @return the response object for the executed request
47      */
48     protected abstract ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException;
49 
50 }

其实就是InterceptingClientHttpRequest类的executeInternal方法,其中,又调用了一个执行器InterceptingRequestExecution的execute,通关判断如果有拦截器注入进来过,就调用拦截器的intercept方法。

这里的拦截器实际上就是在配置阶段注入进RestTemplate实例的负载均衡拦截器LoadBalancerInterceptor实例,可参考上面配置阶段的第2步。

 1 class InterceptingClientHttpRequest extends AbstractBufferingClientHttpRequest {
 2 
 3     private final ClientHttpRequestFactory requestFactory;
 4 
 5     private final List<ClientHttpRequestInterceptor> interceptors;
 6 
 7     private HttpMethod method;
 8 
 9     private URI uri;
10 
11 
12     protected InterceptingClientHttpRequest(ClientHttpRequestFactory requestFactory,
13             List<ClientHttpRequestInterceptor> interceptors, URI uri, HttpMethod method) {
14 
15         this.requestFactory = requestFactory;
16         this.interceptors = interceptors;
17         this.method = method;
18         this.uri = uri;
19     }
20 
21 
22     @Override
23     public HttpMethod getMethod() {
24         return this.method;
25     }
26 
27     @Override
28     public String getMethodValue() {
29         return this.method.name();
30     }
31 
32     @Override
33     public URI getURI() {
34         return this.uri;
35     }
36 
37     @Override
38     protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
39         InterceptingRequestExecution requestExecution = new InterceptingRequestExecution();
40         return requestExecution.execute(this, bufferedOutput);
41     }
42 
43 
44     private class InterceptingRequestExecution implements ClientHttpRequestExecution {
45 
46         private final Iterator<ClientHttpRequestInterceptor> iterator;
47 
48         public InterceptingRequestExecution() {
49             this.iterator = interceptors.iterator();
50         }
51 
52         @Override
53         public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
54             if (this.iterator.hasNext()) {
55                 ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
56                 return nextInterceptor.intercept(request, body, this);
57             }
58             else {
59                 HttpMethod method = request.getMethod();
60                 Assert.state(method != null, "No standard HTTP method");
61                 ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), method);
62                 request.getHeaders().forEach((key, value) -> delegate.getHeaders().addAll(key, value));
63                 if (body.length > 0) {
64                     if (delegate instanceof StreamingHttpOutputMessage) {
65                         StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;
66                         streamingOutputMessage.setBody(outputStream -> StreamUtils.copy(body, outputStream));
67                     }
68                     else {
69                         StreamUtils.copy(body, delegate.getBody());
70                     }
71                 }
72                 return delegate.execute();
73             }
74         }
75     }
76 
77 }

5.负载均衡拦截器调用负载均衡客户端

在负载均衡拦截器LoadBalancerInterceptor类的intercept方法中,又调用了负载均衡客户端LoadBalancerClient实现类的execute方法。

 1 public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
 2 
 3     private LoadBalancerClient loadBalancer;
 4 
 5     private LoadBalancerRequestFactory requestFactory;
 6 
 7     public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
 8             LoadBalancerRequestFactory requestFactory) {
 9         this.loadBalancer = loadBalancer;
10         this.requestFactory = requestFactory;
11     }
12 
13     public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
14         // for backwards compatibility
15         this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
16     }
17 
18     @Override
19     public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
20             final ClientHttpRequestExecution execution) throws IOException {
21         final URI originalUri = request.getURI();
22         String serviceName = originalUri.getHost();
23         Assert.state(serviceName != null,
24                 "Request URI does not contain a valid hostname: " + originalUri);
25         return this.loadBalancer.execute(serviceName,
26                 this.requestFactory.createRequest(request, body, execution));
27     }
28 
29 }

在配置阶段的第1步,可以看到实现类是RibbonLoadBalancerClient。

6.负载均衡客户端调用负载均衡策略选取目标服务实例并发起请求
在RibbonLoadBalancerClient的第一个execute方法以及getServer方法中可以看到,实际上是通过ILoadBalancer的负载均衡器实现类作的chooseServer方法选取一个服务,交给接下来的请求对象发起一个请求。
这里的负载均衡实现类默认是ZoneAwareLoadBalancer区域感知负载均衡器实例,其内部通过均衡策略选择一个服务。
ZoneAwareLoadBalancer的创建可以参考配置阶段的第4步。

  1 public class RibbonLoadBalancerClient implements LoadBalancerClient {
  2 
  3     private SpringClientFactory clientFactory;
  4 
  5     public RibbonLoadBalancerClient(SpringClientFactory clientFactory) {
  6         this.clientFactory = clientFactory;
  7     }
  8 
  9     @Override
 10     public URI reconstructURI(ServiceInstance instance, URI original) {
 11         Assert.notNull(instance, "instance can not be null");
 12         String serviceId = instance.getServiceId();
 13         RibbonLoadBalancerContext context = this.clientFactory
 14                 .getLoadBalancerContext(serviceId);
 15 
 16         URI uri;
 17         Server server;
 18         if (instance instanceof RibbonServer) {
 19             RibbonServer ribbonServer = (RibbonServer) instance;
 20             server = ribbonServer.getServer();
 21             uri = updateToSecureConnectionIfNeeded(original, ribbonServer);
 22         }
 23         else {
 24             server = new Server(instance.getScheme(), instance.getHost(),
 25                     instance.getPort());
 26             IClientConfig clientConfig = clientFactory.getClientConfig(serviceId);
 27             ServerIntrospector serverIntrospector = serverIntrospector(serviceId);
 28             uri = updateToSecureConnectionIfNeeded(original, clientConfig,
 29                     serverIntrospector, server);
 30         }
 31         return context.reconstructURIWithServer(server, uri);
 32     }
 33 
 34     @Override
 35     public ServiceInstance choose(String serviceId) {
 36         return choose(serviceId, null);
 37     }
 38 
 39     /**
 40      * New: Select a server using a 'key'.
 41      * @param serviceId of the service to choose an instance for
 42      * @param hint to specify the service instance
 43      * @return the selected {@link ServiceInstance}
 44      */
 45     public ServiceInstance choose(String serviceId, Object hint) {
 46         Server server = getServer(getLoadBalancer(serviceId), hint);
 47         if (server == null) {
 48             return null;
 49         }
 50         return new RibbonServer(serviceId, server, isSecure(server, serviceId),
 51                 serverIntrospector(serviceId).getMetadata(server));
 52     }
 53 
 54     @Override
 55     public <T> T execute(String serviceId, LoadBalancerRequest<T> request)
 56             throws IOException {
 57         return execute(serviceId, request, null);
 58     }
 59 
 60     /**
 61      * New: Execute a request by selecting server using a 'key'. The hint will have to be
 62      * the last parameter to not mess with the `execute(serviceId, ServiceInstance,
 63      * request)` method. This somewhat breaks the fluent coding style when using a lambda
 64      * to define the LoadBalancerRequest.
 65      * @param <T> returned request execution result type
 66      * @param serviceId id of the service to execute the request to
 67      * @param request to be executed
 68      * @param hint used to choose appropriate {@link Server} instance
 69      * @return request execution result
 70      * @throws IOException executing the request may result in an {@link IOException}
 71      */
 72     public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
 73             throws IOException {
 74         ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
 75         Server server = getServer(loadBalancer, hint);
 76         if (server == null) {
 77             throw new IllegalStateException("No instances available for " + serviceId);
 78         }
 79         RibbonServer ribbonServer = new RibbonServer(serviceId, server,
 80                 isSecure(server, serviceId),
 81                 serverIntrospector(serviceId).getMetadata(server));
 82 
 83         return execute(serviceId, ribbonServer, request);
 84     }
 85 
 86     @Override
 87     public <T> T execute(String serviceId, ServiceInstance serviceInstance,
 88             LoadBalancerRequest<T> request) throws IOException {
 89         Server server = null;
 90         if (serviceInstance instanceof RibbonServer) {
 91             server = ((RibbonServer) serviceInstance).getServer();
 92         }
 93         if (server == null) {
 94             throw new IllegalStateException("No instances available for " + serviceId);
 95         }
 96 
 97         RibbonLoadBalancerContext context = this.clientFactory
 98                 .getLoadBalancerContext(serviceId);
 99         RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
100 
101         try {
102             T returnVal = request.apply(serviceInstance);
103             statsRecorder.recordStats(returnVal);
104             return returnVal;
105         }
106         // catch IOException and rethrow so RestTemplate behaves correctly
107         catch (IOException ex) {
108             statsRecorder.recordStats(ex);
109             throw ex;
110         }
111         catch (Exception ex) {
112             statsRecorder.recordStats(ex);
113             ReflectionUtils.rethrowRuntimeException(ex);
114         }
115         return null;
116     }
117 
118     private ServerIntrospector serverIntrospector(String serviceId) {
119         ServerIntrospector serverIntrospector = this.clientFactory.getInstance(serviceId,
120                 ServerIntrospector.class);
121         if (serverIntrospector == null) {
122             serverIntrospector = new DefaultServerIntrospector();
123         }
124         return serverIntrospector;
125     }
126 
127     private boolean isSecure(Server server, String serviceId) {
128         IClientConfig config = this.clientFactory.getClientConfig(serviceId);
129         ServerIntrospector serverIntrospector = serverIntrospector(serviceId);
130         return RibbonUtils.isSecure(config, serverIntrospector, server);
131     }
132 
133     // Note: This method could be removed?
134     protected Server getServer(String serviceId) {
135         return getServer(getLoadBalancer(serviceId), null);
136     }
137 
138     protected Server getServer(ILoadBalancer loadBalancer) {
139         return getServer(loadBalancer, null);
140     }
141 
142     protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
143         if (loadBalancer == null) {
144             return null;
145         }
146         // Use 'default' on a null hint, or just pass it on?
147         return loadBalancer.chooseServer(hint != null ? hint : "default");
148     }
149 
150     protected ILoadBalancer getLoadBalancer(String serviceId) {
151         return this.clientFactory.getLoadBalancer(serviceId);
152     }
153 
154     /**
155      * Ribbon-server-specific {@link ServiceInstance} implementation.
156      */
157     public static class RibbonServer implements ServiceInstance {
158 
159         private final String serviceId;
160 
161         private final Server server;
162 
163         private final boolean secure;
164 
165         private Map<String, String> metadata;
166 
167         public RibbonServer(String serviceId, Server server) {
168             this(serviceId, server, false, Collections.emptyMap());
169         }
170 
171         public RibbonServer(String serviceId, Server server, boolean secure,
172                 Map<String, String> metadata) {
173             this.serviceId = serviceId;
174             this.server = server;
175             this.secure = secure;
176             this.metadata = metadata;
177         }
178 
179         @Override
180         public String getInstanceId() {
181             return this.server.getId();
182         }
183 
184         @Override
185         public String getServiceId() {
186             return this.serviceId;
187         }
188 
189         @Override
190         public String getHost() {
191             return this.server.getHost();
192         }
193 
194         @Override
195         public int getPort() {
196             return this.server.getPort();
197         }
198 
199         @Override
200         public boolean isSecure() {
201             return this.secure;
202         }
203 
204         @Override
205         public URI getUri() {
206             return DefaultServiceInstance.getUri(this);
207         }
208 
209         @Override
210         public Map<String, String> getMetadata() {
211             return this.metadata;
212         }
213 
214         public Server getServer() {
215             return this.server;
216         }
217 
218         @Override
219         public String getScheme() {
220             return this.server.getScheme();
221         }
222 
223         @Override
224         public String toString() {
225             final StringBuilder sb = new StringBuilder("RibbonServer{");
226             sb.append("serviceId='").append(serviceId).append('\'');
227             sb.append(", server=").append(server);
228             sb.append(", secure=").append(secure);
229             sb.append(", metadata=").append(metadata);
230             sb.append('}');
231             return sb.toString();
232         }
233 
234     }
235 
236 }

代码撸完,总结下。
普通使用RestTemplate请求其他服务时,内部使用的就是常规的http请求实例发送请求。
为RestTemplate增加了@LoanBalanced 注解后,实际上通过配置,为RestTemplate注入负载均衡拦截器,让负载均衡器选择根据其对应的策略选择合适的服务后,再发送请求。

 

posted @ 2021-01-13 18:15  郭慕荣  阅读(308)  评论(0编辑  收藏  举报