ribbon項目通過RestTemplate發起微服務請求,但是知道的都是知道RestTemplate是spring自帶的 那么和ribbon有什么關系呢?

我們找到了@LoadBalanced標注的負載均衡標識
點進去

@Retention(RetentionPolicy.RUNTIME)
ps:這里標識指的是 當編譯完成后 運行保留 在jvm中運行 可以被反射調用
注意上面的綠色注釋LoadBalancerClient來配置它
打開LoadBalancerClient類
里面有三個方法

同時繼承了ServiceInstanceChooser 類
字面意思 服務選擇實例
public interface LoadBalancerClient extends ServiceInstanceChooser { /** * execute request using a ServiceInstance from the LoadBalancer for the specified * service * @param serviceId the service id to look up the LoadBalancer * @param request allows implementations to execute pre and post actions such as * incrementing metrics * @return the result of the LoadBalancerRequest callback on the selected * ServiceInstance */ <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException; /** * execute request using a ServiceInstance from the LoadBalancer for the specified * service * @param serviceId the service id to look up the LoadBalancer * @param serviceInstance the service to execute the request to * @param request allows implementations to execute pre and post actions such as * incrementing metrics * @return the result of the LoadBalancerRequest callback on the selected * ServiceInstance */ <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException; /** * Create a proper URI with a real host and port for systems to utilize. * Some systems use a URI with the logical serivce name as the host, * such as http://myservice/path/to/service. This will replace the * service name with the host:port from the ServiceInstance. * @param instance * @param original a URI with the host as a logical service name * @return a reconstructed URI */ URI reconstructURI(ServiceInstance instance, URI original); }
public interface ServiceInstanceChooser { /** * Choose a ServiceInstance from the LoadBalancer for the specified service * @param serviceId the service id to look up the LoadBalancer * @return a ServiceInstance that matches the serviceId */ ServiceInstance choose(String serviceId); }
ServiceInstance choose(String serviceId); 根據serviceId即服務ID查詢服務
<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException; 根據服務來執行請求內容
URI reconstructURI(ServiceInstance instance, URI original);
拼接請求方式 傳統中是ip:port 現在是服務名稱:port 形式
定位當前類位置 發現相關類

當然太多了 就不仔細說了 有空自己去看
我們關注自動裝配這個類 有關自動裝配相關知識 后面再仔細說
/** * Auto configuration for Ribbon (client side load balancing). * * @author Spencer Gibb * @author Dave Syer * @author Will Tran */ @Configuration @ConditionalOnClass(RestTemplate.class) @ConditionalOnBean(LoadBalancerClient.class) @EnableConfigurationProperties(LoadBalancerRetryProperties.class) public class LoadBalancerAutoConfiguration { @LoadBalanced @Autowired(required = false) private List<RestTemplate> restTemplates = Collections.emptyList(); @Bean public SmartInitializingSingleton loadBalancedRestTemplateInitializer( final List<RestTemplateCustomizer> customizers) { return new SmartInitializingSingleton() { @Override public void afterSingletonsInstantiated() { for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) { for (RestTemplateCustomizer customizer : customizers) { customizer.customize(restTemplate); } } } }; } @Autowired(required = false) private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList(); @Bean @ConditionalOnMissingBean public LoadBalancerRequestFactory loadBalancerRequestFactory( LoadBalancerClient loadBalancerClient) { return new LoadBalancerRequestFactory(loadBalancerClient, 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 new RestTemplateCustomizer() { @Override public void customize(RestTemplate restTemplate) { List<ClientHttpRequestInterceptor> list = new ArrayList<>( restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); } }; } } @Configuration @ConditionalOnClass(RetryTemplate.class) public static class RetryAutoConfiguration { @Bean public RetryTemplate retryTemplate() { RetryTemplate template = new RetryTemplate(); template.setThrowLastExceptionOnExhausted(true); return template; } @Bean @ConditionalOnMissingBean public LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory() { return new LoadBalancedRetryPolicyFactory.NeverRetryFactory(); } @Bean @ConditionalOnMissingBean public LoadBalancedBackOffPolicyFactory loadBalancedBackOffPolicyFactory() { return new LoadBalancedBackOffPolicyFactory.NoBackOffPolicyFactory(); } } @Configuration @ConditionalOnClass(RetryTemplate.class) public static class RetryInterceptorAutoConfiguration { @Bean @ConditionalOnMissingBean public RetryLoadBalancerInterceptor ribbonInterceptor( LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties, LoadBalancedRetryPolicyFactory lbRetryPolicyFactory, LoadBalancerRequestFactory requestFactory, LoadBalancedBackOffPolicyFactory backOffPolicyFactory) { return new RetryLoadBalancerInterceptor(loadBalancerClient, properties, lbRetryPolicyFactory, requestFactory, backOffPolicyFactory); } @Bean @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer( final RetryLoadBalancerInterceptor loadBalancerInterceptor) { return new RestTemplateCustomizer() { @Override public void customize(RestTemplate restTemplate) { List<ClientHttpRequestInterceptor> list = new ArrayList<>( restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); } }; } } }
ps:@ConditionalOnMissingClass當缺少指定的value類時 創建某類
@ConditionalOnClass(RestTemplate.class) RestTemplate類必須存在當前工作環境中
@ConditionalOnBean(LoadBalancerClient.class) 在spring的Bean工程中必須有LoadBalancerClient的實現Bean;
該配置類中 主要做了三件事:
1.創建了一個LoadBalancerInterceptor 負載均衡攔截器 用於對客戶端發起的請求進行攔截,以實現客戶端負載均衡.
2.創建一個RestTemplateCustomizer的Bean,用於給RestTemplate增加
LoadBalancerInterceptor攔截器。
3.維護被@LoadBananced注解修飾的RestTemplate對象列表,並在初始化,通過調用RestTemplateCustomizer實例來給需要的客戶端負載均衡RestTemplate增加攔截器LoadBalancerInterceptor 攔截器
看LoadBalancerInterceptor攔截器是如何將一個普通RestTemplate實現負載均衡的
**
* @author Spencer Gibb * @author Dave Syer * @author Ryan Baxter * @author William Tran */ 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) { // for backwards compatibility 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(); String serviceName = originalUri.getHost(); Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri); return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution)); } }
public interface ClientHttpRequestInterceptor { /** * Intercept the given request, and return a response. The given {@link ClientHttpRequestExecution} allows * the interceptor to pass on the request and response to the next entity in the chain. * * <p>A typical implementation of this method would follow the following pattern: * <ol> * <li>Examine the {@linkplain HttpRequest request} and body</li> * <li>Optionally {@linkplain org.springframework.http.client.support.HttpRequestWrapper wrap} the request to filter HTTP attributes.</li> * <li>Optionally modify the body of the request.</li> * <li><strong>Either</strong> * <ul> * <li>execute the request using {@link ClientHttpRequestExecution#execute(org.springframework.http.HttpRequest, byte[])},</li> * <strong>or</strong> * <li>do not execute the request to block the execution altogether.</li> * </ul> * <li>Optionally wrap the response to filter HTTP attributes.</li> * </ol> * * @param request the request, containing method, URI, and headers * @param body the body of the request * @param execution the request execution * @return the response * @throws IOException in case of I/O errors */ ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException; }
可以看到LoadBalancerInterceptor 實現了重寫ClientHttpRequestInterceptor Http攔截的請求
可以看到攔截器中注入了LoadBalancerClient的實現.當一個被@LoadBalanced 注解修飾的RestTemplate對象向外發起Http請求時用intercept方法 截取出 由於我們host用的是RPC框架 originalUri.getHost();獲取的是服務名 然后在調用之前的LoadBalancerClient execute去執行請求
繼續往下 看LoadBalancerClient的execute實現
@Override public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException { ILoadBalancer loadBalancer = getLoadBalancer(serviceId); Server server = getServer(loadBalancer); 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); } @Override 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; }
可以看到通過
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer);
獲取服務實例
protected Server getServer(ILoadBalancer loadBalancer) { if (loadBalancer == null) { return null; } return loadBalancer.chooseServer("default"); // TODO: better handling of key }

並未使用之前的LoadBalancerClient類的choose來獲取
而是使用netflix ribbon來獲取
public interface ILoadBalancer { void addServers(List<Server> var1); Server chooseServer(Object var1); void markServerDown(Server var1); /** @deprecated */ @Deprecated List<Server> getServerList(boolean var1); List<Server> getReachableServers(); List<Server> getAllServers(); }
主要是這幾個功能
addServers添加服務
chooseServer 選擇服務
markServerDown停止服務
getReachableServers 獲得正常能訪問的服務
getAllServers 獲取所有服務 包括dang機的

ILoadBalancer 的實現擴展以上 而springCloud擴展默認采用ZoneAwareLoadBalancer

2019年4月8日23:59:53 明天上班 休息了