zoukankan      html  css  js  c++  java
  • Spring Cloud 入门Eureka -Consumer服务消费(Ribbon)(二)

    前面一篇介绍了LoadBalancerClient来实现负载均衡, 这里介绍Spring cloud ribbon

    1、ribbon

       Spring Cloud Ribbon 是一个基于Http和TCP的客服端负载均衡工具,它是基于Netflix Ribbon实现的。它不像服务注册中心、配置中心、API网关那样独立部署,但是它几乎存在于每个微服务的基础设施中理解Ribbon对于我们使用Spring Cloud来讲非常的重要,因为负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。

      它内部提供了一个叫做ILoadBalance的接口代表负载均衡器的操作,比如有添加服务器操作、选择服务器操作、获取所有的服务器列表、获取可用的服务器列表等等。

    2、这里我们复制上一章consumer工程,修改pom.xml,增加ribbon依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.example</groupId>
        <artifactId>eurekaRibbon</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <name>eurekaRibbon</name>
        <description>Demo project for Spring Boot</description>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.4.0.RELEASE</version>
            <relativePath /> <!-- lookup parent from repository -->
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-ribbon</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Dalston.SR3</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    
    </project>

    3、修改主类,为RestTemplate增加@LoadBalanced注解

    package com.example.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @EnableDiscoveryClient
    @SpringBootApplication
    public class EurekaRibbonApplication {
        
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaRibbonApplication.class, args);
        }
    }

    4、接口

    package com.example.demo.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    public class ClientRibbonController {
    
        @Autowired
        RestTemplate restTemplate;
    
        @GetMapping("/consumer")
        public String all() {
            // 发起REST请求
            return restTemplate.getForObject("http://eurekaClient/all", String.class);
        }
        
    }

      这里请求的host位置并没有使用一个具体的IP地址和端口的形式,而是采用了服务名的方式组成。Spring Cloud Ribbon有一个拦截器,它能够在这里进行实际调用的时候,自动的去选取服务实例,并将实际要请求的IP地址和端口替换这里的服务名,从而完成服务接口的调用,进而实现自动化:

      然而Ribbon要实现负载均衡自动化配置需要满足如下两个条件:

       1、ConditionalOnClass(RestTemplate.class):RestTemplate类必须存在于当前工程的环境中

       2、ConditionalOnBean(LoadBalancerClient.class):使用@LoadBalanced注解用来给RestTemplate做标记,以使用负载均衡的客户端(LoadBalancerClient)来配置RestTemplate。

      在自动化配置中主要做三件事:

    • 创建一个LoadBalancerInterceptor的Bean,用于实现对客户端发起请求时进行拦截,以实现客户端负载均衡。
    • 创建一个RestTemplateCustomizer的Bean,用于给RestTemplate增加LoadBalancerInterceptor拦截器。
    • 维护了一个被@LoadBalanced注解修饰的RestTemplate对象列表,并在这里进行初始化,通过调用RestTemplateCustomizer的实例来给需要客户端负载均衡的RestTemplate增加LoadBalancerInterceptor拦截器。

    1、条件二LoadBalancerClient

    /**
     * Represents a client side load balancer
     * @author Spencer Gibb
     */
    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);
    }

      我们可以知道 choose()方法根据传入的serviceId服务Id,从负载均衡器选择一个一个对应的服务实例。execute()方法根据serviceId服务ID和请求request来执行请求内容。reconstructURI()方法构建出一个合适的Host:Port的URI。而 RibbonLoadBalancerClient就是LoadBalancerClient的具体实现

    2、Ribbon自动化配置:LoadBalancerAutoConfiguration 

    /**
     * Auto configuration for Ribbon (client side load balancing).
     *
     * @author Spencer Gibb
     * @author Dave Syer
     * @author Will Tran
     */
    @Configuration
    @ConditionalOnClass(RestTemplate.class) //条件 : RestTemplate必须在工程的类路径下
    @ConditionalOnBean(LoadBalancerClient.class)  //条件: Spring 容器中必须包含LoadBalancerClient的实现,即RibbonLoadBalancerClient
    @EnableConfigurationProperties(LoadBalancerRetryProperties.class) //启动重试功能,可以spring.cloud.loadbalancer.retry=false,取消重试,默认参数为true
    public class LoadBalancerAutoConfiguration {
     
        @LoadBalanced
        @Autowired(required = false)
        private List<RestTemplate> restTemplates = Collections.emptyList(); //维护一个RestTemplate列表,通过LoadBalanced来注解。
     
        @Bean
        public SmartInitializingSingleton loadBalancedRestTemplateInitializer( //加载初始话自定义的restTeplate,实质是初始化InterceptingHttpAccessor具体调用
                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)
        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
            public RetryLoadBalancerInterceptor ribbonInterceptor(
                    LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties,
                    LoadBalancedRetryPolicyFactory lbRetryPolicyFactory,
                    LoadBalancerRequestFactory requestFactory) {
                return new RetryLoadBalancerInterceptor(loadBalancerClient, retryTemplate(), properties,
                        lbRetryPolicyFactory, requestFactory);
            }
     
            @Bean
            @ConditionalOnMissingBean
            public RestTemplateCustomizer restTemplateCustomizer( //自定义RestTemplate ,实质是初始化InterceptingHttpAccessor
                    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);
                    }
                };
            }
        }
    }

    具体可以看下https://www.cnblogs.com/duanxz/p/7504947.html,源码介绍

  • 相关阅读:
    局域网中CSMA/CD协议的应用
    RIP及距离向量算法
    网桥与以太网交换机
    C++ String
    C++ Input & Output
    Shell Script(1)----variable compare
    python--内建函数(1)
    python--data type
    python--compile
    python--help
  • 原文地址:https://www.cnblogs.com/zwdx/p/9139597.html
Copyright © 2011-2022 走看看