美文网首页
SpringCloud(二)服务调用 ribbon和feign

SpringCloud(二)服务调用 ribbon和feign

作者: 茧铭 | 来源:发表于2019-04-30 19:35 被阅读0次

    在微服务架构中,每个业务模块都被看待为一个独立的服务。服务与服务之间基于Restful 风格的接口相互通信。Spring cloud有两种调用方式,分别是使用ribbon + restTemplate 和 feign。

    1、事先准备(可快速略过)

    在开始之前,我在本地写了一个Order服务,两个Product服务,并实现了一些逻辑


    jiaxini.img

    以findByProductIdIn接口为例,这个接口是供订单调用的接口。逻辑是订单服务拿到几种产品的productId的List集合,商品服务查询这几种商品的详情并返回结果。首先我在postman测试一下这个接口的功能。(但我自己非常不推荐传入集合作为参数的操作)


    request
    response

    2、Ribbon + Rest 服务消费

    在消费服务的order项目中加入依赖

    <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
    

    这儿我分别用三种方式去实现接口的调用;

    方式一:利用restTemplate

    我之前写过一些介绍restTemplate的基本使用的文章,这里可以直接拿来使用

    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:3003/product/findByProductIdIn";
    List<String> stringList = Arrays.asList("8216e50c-3826-4a2f-bb54-3a4b6f408b10", "4ea84cda-fca8-443b-a957-51c621bc8330");
    List list = restTemplate.postForObject(url, stringList, List.class);
    log.info(list.toString());
    

    这样做的弊端是我的Url比较固定,ip和端口号集中,我只能通过一些restTemplate提供的添加参数的方法去实现逻辑。在微服务的情况下,如果一台服务器部署了两个微服务,就只能去找某一个了,也没有了高可用。

    方法二:使用loadBalancerClient类
        @Autowired
        private LoadBalancerClient loadBalancerClient;
    
        @GetMapping(value = "/method2")
        public void useLoadBalancerClient(){
            RestTemplate restTemplate = new RestTemplate();
            //发现服务
            ServiceInstance serviceInstance = loadBalancerClient.choose("product");
            String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/product/findByProductIdIn";
            List<String> stringList = Arrays.asList("8216e50c-3826-4a2f-bb54-3a4b6f408b10",
                                         "4ea84cda-fca8-443b-a957-51c621bc8330");
            List list = restTemplate.postForObject(url, stringList, List.class);
            log.info(list.toString());
        }
    

    这样做对比直接使用restTemplate固定Url的形式,有一个好处就是首先利用LoadBalancerClient 去发现serviceId为“product”的服务,然后再取这个服务的host和port去拼接请求。这样做就避免了写死ip和端口的情况。再者在LoadBalancerClient中实际上是引入了一种 IRULE 的东西,它定义了如何去使用服务的规则。比如说product提供了多个服务,可以选择使用轮询、随机等方式去访问服务,具体情况具体实现。

    源码阅读:
    ServiceInstance serviceInstance = loadBalancerClient.choose("product");





    可以发现springCloud默认使用了RoundRobinRule去定义调用规则,也就是轮询,如果过服务会按照1->2->3->1->2->3->1这样的方式去依次调用我们指定的服务。就像下图的结果这样,3003和3004是商品服务的端口。

    当然除了轮询之外还有一些别的emmmm(并不认识,但很感人)的规则,当然也可以自己实现IRULE并注册一个自定义的方式到Bean里。

    切换这个Rule也比较简单,这个类里给我们了一个setRule的方法,将要用的IRULE的Bean注册到里面应该就能生效了,这里我并没有尝试,有兴趣的大哥麻烦试一下并传唤我。不过我在网上看到另外一种更改的方法,即直接修改配置。如下图所示
    PRODUCT是服务名serviceId
    IRULE类是全路径

    方法三:

    先创建一个配置类,定义RestTemplate的Bean,加入注解@LoadBalanced

    @Configuration
    public class RestTemplateConfig {
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
        
    }
    
    @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping(value = "/method3")
        public void useLoadBalancedAnnotation(){
            List<String> stringList = Arrays.asList("8216e50c-3826-4a2f-bb54-3a4b6f408b10", "4ea84cda-fca8-443b-a957-51c621bc8330");
            // 第一个product是服务名serviceId,第二个是请求路径的一部分
            List result = restTemplate.postForObject("http://product/product/findByProductIdIn", stringList, List.class);
            log.info(result.toString());
        }
    
    请求成功

    这个注解的原理和方法二类似,它的底层用的就是LoadBalancerClient实现。

    3、Feign

    feign是在ribbon的基础上做了一些改进。它采用接口的方式, 只需要创建一个接口,然后在上面添加注解即可 ,将需要调用的其他服务的方法定义成抽象方法即可, 不需要自己构建http请求。
    个人选择使用feign的原因是因为feign接口较ribbon拼接请求而言,更加的直观地展示了需要的参数和返回类型,而接口调用的方式,会让我觉得它就是一个service,我可以去正常调用它的接口。

    首先加入依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    

    在启动类上加入注解

    /**  basePackages 限定包路径  */
    @SpringBootApplication
    @EnableEurekaClient
    @EnableFeignClients(basePackages = "com.jiaxini.order.feign")
    public class OrderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    }
    

    feign接口类编写

    @FeignClient(value = "product")
    public interface ProductFeign {
    
        /**  查询根据idList查询商品列表  */
        @PostMapping("/product/findByProductIdIn")
        public List<ProductInfoSimplifyVO> findByProductIdIn(@RequestBody List<String> idList);
    
        /**  订单减库:根据商品Id减去一定数量的库存  */
        @PostMapping("/product/reduceProductStock")
        public boolean reduceProductStock(@RequestBody List<ReduseProductForm> reduseProductFormList);
    
    }
    

    @FeignClient:表明这是一个feign接口类
    value:填写调用服务的serviceId
    接口方法则与调用接口一致(方法名可以自定义)

    具体使用

    打完收工!

    相关文章

      网友评论

          本文标题:SpringCloud(二)服务调用 ribbon和feign

          本文链接:https://www.haomeiwen.com/subject/msnynqtx.html