前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud 三种服务调用方式,你学会了吗?

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

作者头像
芋道源码
发布2022-09-23 15:13:15
9760
发布2022-09-23 15:13:15
举报
文章被收录于专栏:芋道源码1024

点击上方“芋道源码”,选择“设为星标

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

来源:blog.csdn.net/qq_21790633/

article/details/105182750


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

  • Spring DiscoveryClient
  • 支持 Ribbon 的 RestTemplate
  • Feign客户端

服务测试环境

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

主要步骤如下:

1.引入Eureka所需的依赖

代码语言:javascript
复制
<!--eureka服务端-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka-server</artifactId>
  </dependency>
<!--客户端-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

2.修改配置文件

服务端:

代码语言:javascript
复制
eureka:
 instance:
  hostname: eureka9001.com #eureka服务端的实例名称
  instance-id: eureka9001
client:
  register-with-eureka: false #false表示不向注册中心注册自己
  fetch-registry: false # #false 表示自己就是注册中心,职责就是维护服务实例,并不需要去检索服务
  service-url:
  defaulteZone: http://127.0.0.1:9001

客户端1:

代码语言:javascript
复制
server:
  port: 8002
spring:
  application:
    name: licensingservice
eureka:
  instance:
    instance-id: licensing-service-8002
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://127.0.0.1:9001/eureka/,

客户端2:

代码语言:javascript
复制
server:
 port: 8002
spring:
 application:
   name: licensingservice
eureka:
 instance:
   instance-id: licensing-service-8002
   prefer-ip-address: true
 client:
   register-with-eureka: true
   fetch-registry: true
   service-url:
     defaultZone: http://127.0.0.1:9001/eureka/,    

一组微服务的不同实例采办服务名称不同,不同的实例ID不同,不同,spring.application.nameeureka.instance.instance-id

3.启动服务

服务端:

代码语言:javascript
复制
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerPort9001_App {
  public static void main(String[] args) {
    SpringApplication.run(EurekaServerPort9001_App.class,args);
  }
}

客户端:

代码语言:javascript
复制
@SpringBootApplication
@RefreshScope
@EnableEurekaClient
public class LicenseApplication_8002 {
    public static void main(String[] args) {
        SpringApplication.run(LicenseApplication_8002.class, args);
    }
}

4.测试

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

标签:

注意:Eureka通过两次服务检测均到通过,服务将在间隔10秒内成功启动服务注册等待30秒。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

消费者

1.发现客户端方式

服务中既是服务是微信也可以是调用者,消费者配置和上面配置的大体参考一致,依赖及配置服务端启动方式EnableEurekaClient:监听启动。

代码语言:javascript
复制
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class ConsumerApplication_7002 {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication_7002.class, args);
    }
}

核心配置类:

代码语言:javascript
复制
@Component
public class ConsumerDiscoveryClient {

  @Autowired
  private DiscoveryClient discoveryClient;

  public ServiceInstance getServiceInstance() {
    List<ServiceInstance> serviceInstances = discoveryClient.getInstances("licensingservice");
    if (serviceInstances.size() == 0) {
      return null;
    }
    return serviceInstances.get(0);
  }

  public String getUrl(String url) {
    ServiceInstance serviceInstance=this.getServiceInstance();
    if (serviceInstance==null)
      throw new RuntimeException("404 ,NOT FOUND");
    String urlR=String.format(url,serviceInstance.getUri().toString());
    return urlR;
  }
}

通过DiscoveryClient从尤里卡中获取licensingservice服务的实例,并返回第一个实例。

测试控制器

代码语言:javascript
复制
@RestController
@RequestMapping("test")
public class TestController {
  //注意必须new,否则会被ribbon拦截器拦截,改变URL行为
  private RestTemplate restTemplate=new RestTemplate();
  @Autowired
  private ConsumerDiscoveryClient consumerDiscoveryClient;
  @RequestMapping("/getAllEmp")
  public List<Emp> getAllLicense(){
    String url=consumerDiscoveryClient.getUrl("%s/test/getAllEmp");
    return restTemplate.getForObject(url,List.class);
  }
}

测试:

  1. 调试信息

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

  1. 页面返回信息

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

2.Ribbon方式功能的Spring RestTemplate

同上。

核心配置类:

代码语言:javascript
复制
//指明负载均衡算法
@Bean
public IRule iRule() {
  return new RoundRobinRule();
}

@Bean
@LoadBalanced //告诉Spring创建一个支持Ribbon负载均衡的RestTemplate
public RestTemplate restTemplate() {
  return new RestTemplate();
}

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

测试类:

代码语言:javascript
复制
@RestController
@RequestMapping("rest")
public class ConsumerRestController {

    @Autowired
    private RestTemplate restTemplate;
    private final static String SERVICE_URL_PREFIX = "http://LICENSINGSERVICE";

    @RequestMapping("/getById")
    public Emp getById(Long id) {
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
        paramMap.add("id", id);
        return restTemplate.postForObject(SERVICE_URL_PREFIX + "/test/getById", paramMap, Emp.class);
    }
}

测试结果:

  • 第一次:
  • 第二次:
  • 第三次:

因为采用轮询平均方式分别使用不同的服务实例,未区别,将名称确定了一定的。

这上面,Ribbon 是对第一种方式的封装方式和不同的负载率。 Feign的方式则大大降低了开发客户端和提升速度。

3.feign客户端方式

引入依赖:

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

主要代码:

代码语言:javascript
复制
@FeignClient(value = "LICENSINGSERVICE",fallbackFactory = ServiceImp.class)
public interface ServiceInterface {

  @RequestMapping("/test/getById")
  Emp getById(@RequestParam("id") Long id);

  @RequestMapping("/test/getLicenseById")
  License getLicenseById(@RequestParam("id") Long id);

  @RequestMapping("/test/getAllEmp")
  List<Emp> getAllLicense();
}
@Component
public class ServiceImp implements FallbackFactory<ServiceInterface> {

    @Override
    public ServiceInterface create(Throwable throwable) {
        return new ServiceInterface() {
            @Override
            public Emp getById(Long id) {
                Emp emp = new Emp();
                emp.setName("i am feign fallback create");
                return emp;
            }

            @Override
            public License getLicenseById(Long id) {
                return null;
            }

            @Override
            public List<Emp> getAllLicense() {
                return null;
            }
        };
    }
}

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

主启动类:

代码语言:javascript
复制
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class Consumer_feign_Application_7004 {
    public static void main(String[] args) {
        SpringApplication.run(Consumer_feign_Application_7004.class, args);
    }
}

测试类:

代码语言:javascript
复制
@RestController
@RequestMapping("rest")
public class ConsumerRestController {
  @Autowired
  private ServiceInterface serviceInterface;

  @Autowired
  private RestTemplate restTemplate;
  @RequestMapping("/getById")
  public Emp getById(Long id) {
    return serviceInterface.getById(id);
  }
}

测试结果:

  • 正常测试:
  • 关闭两个实例,模拟服务实例死亡:

假装能够故障服务调用,也可以实现调用的服务时,友好的信息。

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



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

代码语言:javascript
复制
文章有帮助的话,在看,转发吧。谢谢支持哟 (*^__^*)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 芋道源码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 服务测试环境
    • 1.引入Eureka所需的依赖
      • 2.修改配置文件
        • 3.启动服务
          • 4.测试
          • 消费者
            • 1.发现客户端方式
              • 2.Ribbon方式功能的Spring RestTemplate
                • 3.feign客户端方式
                相关产品与服务
                消息队列 TDMQ
                消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档