• SpringCloud 三种服务调用方式,你学会了吗?


    本文主要介绍SpringCloud中三种服务调用方式:

    • Spring DiscoveryClient

    • 支持Ribbon的RestTemplate

    • Feign客户端

    搭建服务测试环境

    测试中,服务发现层采用Netflix的Eureka搭建。

    主要步骤如下:

    1.引入Eureka所需依赖

    1. <!--eureka服务端-->
    2.   <dependency>
    3.     <groupId>org.springframework.cloud</groupId>
    4.     <artifactId>spring-cloud-starter-eureka-server</artifactId>
    5.   </dependency>
    6. <!--客户端-->
    7. <dependency>
    8.   <groupId>org.springframework.cloud</groupId>
    9.   <artifactId>spring-cloud-starter-eureka</artifactId>
    10. </dependency>

    2.修改配置文件

    服务端:

    1. eureka:
    2.  instance:
    3.   hostname: eureka9001.com #eureka服务端的实例名称
    4.   instance-id: eureka9001
    5. client:
    6.   register-with-eureka: false #false表示不向注册中心注册自己
    7.   fetch-registry: false # #false 表示自己就是注册中心,职责就是维护服务实例,并不需要去检索服务
    8.   service-url:
    9.   defaulteZone: http://127.0.0.1:9001

    客户端1:

    1. server:
    2.   port: 8002
    3. spring:
    4.   application:
    5.     name: licensingservice
    6. eureka:
    7.   instance:
    8.     instance-id: licensing-service-8002
    9.     prefer-ip-address: true
    10.   client:
    11.     register-with-eureka: true
    12.     fetch-registry: true
    13.     service-url:
    14.       defaultZone: http://127.0.0.1:9001/eureka/,

    客户端2:

    1. server:
    2.  port: 8002
    3. spring:
    4.  application:
    5.    name: licensingservice
    6. eureka:
    7.  instance:
    8.    instance-id: licensing-service-8002
    9.    prefer-ip-address: true
    10.  client:
    11.    register-with-eureka: true
    12.    fetch-registry: true
    13.    service-url:
    14.      defaultZone: http://127.0.0.1:9001/eureka/,    

    一组微服务的不同实例采服务名相同,不同的实例Id区分,分别对应,spring.application.name 和eureka.instance.instance-id

    3.启动服务

    服务端:

    1. @SpringBootApplication
    2. @EnableEurekaServer
    3. public class EurekaServerPort9001_App {
    4.   public static void main(String[] args) {
    5.     SpringApplication.run(EurekaServerPort9001_App.class,args);
    6.   }
    7. }

    客户端:

    1. @SpringBootApplication
    2. @RefreshScope
    3. @EnableEurekaClient
    4. public class LicenseApplication_8002 {
    5.     public static void main(String[] args) {
    6.         SpringApplication.run(LicenseApplication_8002.class, args);
    7.     }
    8. }

    4.测试

    进入到Eureka服务端地址,我这是127.0.0.1:9001,可以查看注册到注册中心的服务。

    如图:

    注意事项:Eureka通过三次心跳检测均通过,服务才会成功注册到注册中心,默认每次间隔10s,及初次启动服务需等待30s才能在Eureka中看到注册服务。

    消费者搭建

    1.Discover Client方式

    微服务中服务既是消费者也可以是调用者,因此消费者配置和上面服务配置大体一致,依赖及配置参考上面服务端搭建方式。启动主类添加EnableEurekaClient注释:

    1. @SpringBootApplication
    2. @EnableEurekaClient
    3. @EnableDiscoveryClient
    4. public class ConsumerApplication_7002 {
    5.     public static void main(String[] args) {
    6.         SpringApplication.run(ConsumerApplication_7002.class, args);
    7.     }
    8. }

    核心配置类:

    1. @Component
    2. public class ConsumerDiscoveryClient {
    3.   @Autowired
    4.   private DiscoveryClient discoveryClient;
    5.   public ServiceInstance getServiceInstance() {
    6.     List<ServiceInstance> serviceInstances = discoveryClient.getInstances("licensingservice");
    7.     if (serviceInstances.size() == 0) {
    8.       return null;
    9.     }
    10.     return serviceInstances.get(0);
    11.   }
    12.   public String getUrl(String url) {
    13.     ServiceInstance serviceInstance=this.getServiceInstance();
    14.     if (serviceInstance==null)
    15.       throw new RuntimeException("404 ,NOT FOUND");
    16.     String urlR=String.format(url,serviceInstance.getUri().toString());
    17.     return urlR;
    18.   }
    19. }

    通过DiscoveryClient从Eureka中获取licensingservice服务的实例数组,并返回第一个实例。

    测试Controller

    1. @RestController
    2. @RequestMapping("test")
    3. public class TestController {
    4.   //注意必须new,否则会被ribbon拦截器拦截,改变URL行为
    5.   private RestTemplate restTemplate=new RestTemplate();
    6.   @Autowired
    7.   private ConsumerDiscoveryClient consumerDiscoveryClient;
    8.   @RequestMapping("/getAllEmp")
    9.   public List getAllLicense(){
    10.     String url=consumerDiscoveryClient.getUrl("%s/test/getAllEmp");
    11.     return restTemplate.getForObject(url,List.class);
    12.   }
    13. }

    测试:

    1. 调试信息

    从该图可以直观看到licensingservice,拥有两个服务实例,并可以查看实例信息。

    1. 页面返回信息

    成功查询到数据库存储信息。

    2.Ribbon功能的Spring RestTemplate方式

    依赖同上。

    核心配置类:

    1. //指明负载均衡算法
    2. @Bean
    3. public IRule iRule() {
    4.   return new RoundRobinRule();
    5. }
    6. @Bean
    7. @LoadBalanced //告诉Spring创建一个支持Ribbon负载均衡的RestTemplate
    8. public RestTemplate restTemplate() {
    9.   return new RestTemplate();
    10. }

    设置负载均衡方式为轮询方式。

    测试类:

    1. @RestController
    2. @RequestMapping("rest")
    3. public class ConsumerRestController {
    4.     @Autowired
    5.     private RestTemplate restTemplate;
    6.     private final static String SERVICE_URL_PREFIX = "http://LICENSINGSERVICE";
    7.     @RequestMapping("/getById")
    8.     public Emp getById(Long id) {
    9.         MultiValueMap<StringObject> paramMap = new LinkedMultiValueMap<StringObject>();
    10.         paramMap.add("id", id);
    11.         return restTemplate.postForObject(SERVICE_URL_PREFIX + "/test/getById", paramMap, Emp.class);
    12.     }
    13. }

    测试结果:

    • 第一次:

    • 第二次:

    • 第三次:

    因为采用轮询负载均衡方式分别调用不同服务实例,未区别,将name做出了一定更改。

    以上两种方式对比,Ribbon方式是对第一种方式的封装且内置不同的负载算法,支持自定义。使用更加简单,但此两次均需编写RestTemplate的请求方法,较为繁琐且容易出错,第三种方式Feign客户端则极大的降低了开发难度和提升速度。

    3.feign客户端方式

    引入依赖:

    1. <dependency>
    2.     <groupId>org.springframework.cloud</groupId>
    3.     <artifactId>spring-cloud-starter-feign</artifactId>
    4. </dependency>

    主要代码:

    1. @FeignClient(value = "LICENSINGSERVICE",fallbackFactory = ServiceImp.class)
    2. public interface ServiceInterface {
    3.   @RequestMapping("/test/getById")
    4.   Emp getById(@RequestParam("id") Long id);
    5.   @RequestMapping("/test/getLicenseById")
    6.   License getLicenseById(@RequestParam("id") Long id);
    7.   @RequestMapping("/test/getAllEmp")
    8.   List getAllLicense();
    9. }
    1. @Component
    2. public class ServiceImp implements FallbackFactory<ServiceInterface> {
    3.     @Override
    4.     public ServiceInterface create(Throwable throwable) {
    5.         return new ServiceInterface() {
    6.             @Override
    7.             public Emp getById(Long id) {
    8.                 Emp emp = new Emp();
    9.                 emp.setName("i am feign fallback create");
    10.                 return emp;
    11.             }
    12.             @Override
    13.             public License getLicenseById(Long id) {
    14.                 return null;
    15.             }
    16.             @Override
    17.             public List<EmpgetAllLicense() {
    18.                 return null;
    19.             }
    20.         };
    21.     }
    22. }

    采用接口模式开发,通过注解指明服务名以及后备方法,在服务表现不佳时,方便返回默认的结果,而不是一个不友好的错误。

    主启动类:

    1. @SpringBootApplication
    2. @EnableEurekaClient
    3. @EnableFeignClients
    4. public class Consumer_feign_Application_7004 {
    5.     public static void main(String[] args) {
    6.         SpringApplication.run(Consumer_feign_Application_7004.class, args);
    7.     }
    8. }

    测试类:

    1. @RestController
    2. @RequestMapping("rest")
    3. public class ConsumerRestController {
    4.   @Autowired
    5.   private ServiceInterface serviceInterface;
    6.   @Autowired
    7.   private RestTemplate restTemplate;
    8.   @RequestMapping("/getById")
    9.   public Emp getById(Long id) {
    10.     return serviceInterface.getById(id);
    11.   }
    12. }

    测试结果:

    • 正常测试:

    • 关闭两个服务实例,模拟服务实例死亡:

    Feign除了能简化服务调用,也可以实现当调用的服务失败时,友好的反馈信息。

    此三种调用方式,由低至上,从不同层次实现了SpringCloud中的微服务互相调用。

  • 相关阅读:
    爬虫 — Js 逆向案例五闪职网登录
    实验三 循环结构程序设计(Python)
    行车记录仪格式化了还能恢复吗?
    MongoDB教程(三):mongoDB用户管理
    基于stm32单片机智能交通灯设计Proteus仿真
    PHP代码审计3—系统重装漏洞
    反射(获取成员变量,获取成员方法)
    Mac 手动安装 sshpass
    前端发起请求,后端响应请求的整个过程
    [附源码]计算机毕业设计企业售后服务管理系统Springboot程序
  • 原文地址:https://blog.csdn.net/m0_71777195/article/details/126688356