zoukankan      html  css  js  c++  java
  • 服务间调用--feign跟ribbon

      微服务一般来说当然是多服务多实例的,那么这些服务之间如何相互调用呢?spring cloud之前我们用dubbo,把服务开放出来,在xml配好后就可以像调用本地service一样调用其它模块的服务了;spring cloud当然也可以做到这一点,这就是feign。dubbo除了能调用其它模块服务,还实现了服务的负载均衡,对于spring cloud而言,这就是ribbon。
      我们看一下一个简单的调用示例:
    --------------------------------------------------------------------------------------------------------------------------------
      1、服务提供者搭建
      作为一个示例项目,仅需引入最基本的web跟eureka依赖即可。
      xml主要内容:
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    

      application.yml内容:

    spring:
      application:
        name: sms-module
    info:
      name: author:wzy,class:develop,tel:17301394307
    
    server:
      port: 9001
    
    eureka:
      client:
        registerWithEureka: true
        fetchRegistry: true
        serverUrl:
          defaultZone: http://127.0.0.1:8761/eureka
      instance:
        #心跳间隔
        leaseRenewalIntervalInSeconds: 10
    
      conttoller类内容:
    @RequestMapping("/sms")
    @RestController
    public class SmsController {
        @Autowired
        MessageService msgService;
    
        @RequestMapping("/getPerson")
        public PersonVo getPerson(String phoneNumber){
            PersonVo person = new PersonVo();
            person.setName("张三");
            person.setAge(20);
            person.setSex('男');
            person.setNativePlace("山东菏泽");
            person.setIdentityCardId("37132519900809244x");
            person.setPhoneNumber("13100001111");
    
            System.out.println("sms收到的phoneNumber : "+phoneNumber);
            return person;
        }
    }
    
      当然,启动类我们不能忘了@EnableEurekaClient,启动三个示例,端口分别为9001、9002、9003
      2、消费者搭建
      pom文件主要依赖:
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
    </dependency>
      其实本示例中的内容较为简单,ribbon的starter可以不引入,本例使用的ribbon内容在spring-cloud-netflix-core包中。
      application.yml内容:
    spring:
      application:
        name: feign-demo
    info:
      name: cloud feign-demo
    server:
      port: 8080
    
    eureka:
      client:
        register-with-eureka: true
        fetch-registry: true
        serviceUrl:
          defaultZone: http://127.0.0.1:8761/eureka/
    
    feign:
      hystrix:
        enable: false  
      先说feign部分的内容:
      feign是netflix的一个子项目,能实现基于http的rest api的访问。当然这个功能用apache的httpclient也可以实现,但用起来不方便,而feign使用起来非常友好。spring cloud feign是spring cloud把原生feign封装之后产生的。访问远程的微服务接口,我们希望能像访问本地service一样容易的进行访问,这样,对于每一个微服务我们都需要一个“工具类”client,比如:

    //暂无熔断,因此无fallback回调
    @FeignClient(name = "sms-module")    //name对应的是服务名称
    public interface FeignSmsClient {   //注意,这里是接口
        @RequestMapping(value = "/sms/getPerson")    //类似于controller中的路径映射,但这不是controller,而是请求的发起端
        PersonVo queryPerson(@RequestParam("phoneNumber") String phoneNumber);   //普通的参数,如果是uri中的参数,应该用@PathParam,post请求还有@Body模板
    }
      这个地方,如果有多个微服务需要我们访问,那就需要多个feignClient接口类,每个对应的服务名称不同而已,controller使用的时候直接注解引入即可。
      controller中使用:
    @RequestMapping("/demo")
    @RestController
    public class TestClientController {
        @Autowired
        FeignSmsClient feignClient;
    
        @RequestMapping("/test2")
        public PersonVo myGetPerson2(){
            PersonVo personVo = null;
            personVo = feignClient.queryPerson("15611273879");
            return personVo;
        }
    }
      启动类加@EnableFeignClients,启动后访问:
      可以看到能正确返回结果,多次访问,可以看到sms-module的三个实例均有响应,表明cloud的feign默认已经实现了某种策略的负载均衡机制(默认是轮询)。
      有默认的负载机制当然好,但如果我们不想使用默认的负载机制,该怎么配置呢?有两种配置方法:1、yml配置文件 2、java类配置。
      yml配置文件,就是每个微服务单独配置,内容大致如下:
    sms-module:    #服务名
    	ribbon:
    	    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule    #负载策略配置
    
      个人觉得,当服务比较多的时候,会占用比较多的内容,看起来有点乱,建议用java类配置或者单独作为一个配置文件跟配置中心搭配使用。  
      java配置类内容如下:
    public class MyBalance {
        @Bean
        public IRule ribbonRule(){
            System.out.println("------------------ribbon Rule  -------------");
            return new RandomRule();
        }
    }
      当然,只是这么写是没用的,还要让spring 容器读到这个内容,不同服务可能使用的负载策略也不一样:
    @RibbonClients(value = {
            @RibbonClient(name="sms-module",configuration = MyBalance.class), 
            @RibbonClient(name="consumer-module",configuration = MyBalance2.class)
    })
      以上是feign跟ribbon搭配使用的情况,如果项目不适用feign单独使用ribbon的话该怎么用呢?
      ribbon是做负载策略的,那跟其它服务进行交互的任务由谁完成呢?RestTemplate闪亮登场。RestTemplate跟jdbcTemplate,jmsTemplate一样,是spring设计的为执行复杂任务而提供的一个具有默认行为的简单方法。RestTemplate是用来消费rest服务的,所以RestTemplate的主要方法都与rest的http协议的一些方法紧密相连,例如head、get、post、put、delete跟options等,这些协议在RestTemplate中对应的方法为headForHeaders()、getForObject()、postForObject、put()跟delete()等。
      restTemplate可以直接注解引入使用,但要先加@LoadBalanced修饰后才会跟负载机制关联。
      负载均衡器的核心是LoadBalancerClient,它可以获取负载均衡的服务提供者的实例信息,使用如下:
    @RequestMapping("/demo")
    @RestController
    public class TestClientController {
        @Autowired
        private RestTemplate restTemplate;
        @Autowired
        private LoadBalancerClient loadBalancerClient;
    
        @RequestMapping("/test")
        public PersonVo myGetPerson(){
            ServiceInstance instance = loadBalancerClient.choose("sms-module");
            System.out.println("本次执行的实例是:"+instance.getHost()+":"+instance.getPort());
    
            PersonVo personVo = null;
            personVo = restTemplate.getForObject("http://sms-module/sms/getPerson?phoneNumber=17301394307",PersonVo.class);  //注意这里http://后跟的是服务名,而不是实例的ip+port
            return personVo;
        }
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
      访问结果如下:
      注意:restTemplate请求的时候,后边跟的是服务名而不是ip+端口号。
    --------------------------------------------------------------------------------------------------------------------------------
    先这样吧,更深的内容以后再补。
     

  • 相关阅读:
    提取PDF内容保存到Excel--Python3实现
    Python正则表达式常用语法
    我的数学建模之路
    Git基本用法
    PDF电子发票内容提取
    获取代理IP地址
    adb 命令 exec-out 直接截图保存到电脑出错的解决办法
    Python基础十一:使用模块
    MSTP生成树实验
    防火墙双机热备概念
  • 原文地址:https://www.cnblogs.com/nevermorewang/p/9311415.html
Copyright © 2011-2022 走看看