服务间的通信(RestTemplate +Ribbon+Feign):

news2024/12/24 9:32:45

服务之间的依赖:

其实根据上图我们发现会员管理服务其实是依赖于我们图书的这个服务的,那么为什么要依赖于图书这个服务呢,因为会员服务想要进行借阅图书的时候,必须要对图书模块的图书的库存等做校验才可以,所以member服务要调用book服务的API了

首先我们要对book这个服务进行改写,首先book服务的service层的代码:

package com.laosan.book.service;

import com.laosan.book.entity.Book;
import com.laosan.book.exception.BookNotFoundException;
import com.laosan.book.repository.BookRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class BookService {
    @Autowired
    private BookRepository repository;

    public List<Book> findAll() {
        List<Book> bookList = repository.findAll();
        return bookList;
    }

    /**
     * 根据图书Id查询某个图书信息
     * @return
     */
    public Book getInfo(Long bid) {
        Optional<Book> optional = repository.findById(bid);
        Book book = null;
        //第一个判断这个书是否存在
        if(optional.isPresent()) {
            book = optional.get();   //获得对应的对象
        }
        else {
            //如果不存在抛出一个对应的异常信息
            throw new BookNotFoundException("图书"+bid+"未找到");
        }
        return book;
    }
}

自定义异常类:

package com.laosan.book.exception;
/**
 * book自定义异常信息
 */
public class BookNotFoundException extends RuntimeException{
    public BookNotFoundException(String message) {
        super(message);
    }
}

 然后book项目的Controller中添加一个方法:

package com.laosan.book.controller;
@RestController
@CrossOrigin       //进行该Controller的跨域操作
public class BookController {
    @Autowired
    private BookService bookService;
    /**
     * book模块返回所有的操作
     * @return
     */
    @GetMapping("/list")
    public Map<String, Object> list() {
        Map<String, Object> map = new HashMap<>();
        try {
            List<Book> list = bookService.findAll();
            map.put("code", "0");
            map.put("message", "success");
            map.put("data", list);
        } catch (Exception e) {
            e.printStackTrace();
            map.put("code", e.getClass().getSimpleName());
            map.put("message", e.getMessage());
        }
        return map;
    }

    @GetMapping("/info")
    public Map<String, Object> info(Long bid) {
        Map<String, Object> map = new HashMap<>();
        try {
            Book book = bookService.getInfo(bid);
            map.put("code", "0");
            map.put("message", "success");
            map.put("data", book);
        } catch (Exception e) {
            e.printStackTrace();
            map.put("code", e.getClass().getSimpleName());
            map.put("message", e.getMessage());
        }
        return map;
    }
}

重启所有服务:

首先对book进行单体应用测试,输入地址进行测试:

现在的问题是我们刚刚查询出来的根据bid查询的数据并不是给book服务来用的而是给member服务来用的,那么现在我们就要开始应用远程调用的操作了

我们先在member项目的Controller里面进行相应的测试操作:

package com.laosan.member.controller;
@Controller
@CrossOrigin    //跨域问题的解决
public class MemberController {
    @Autowired
    private MemberService memberService;
    @GetMapping("/check")
    @ResponseBody
    public Map<String, Object> checkMobile(String mobile, HttpServletResponse response) {
        //response.setHeader("Access-Control-Allow-Origin", "*");
        Map<String, Object> map = new HashMap<String, Object>();
        try{
            Member member = memberService.checkByMobile(mobile);
            map.put("code", "0");
            map.put("message", "success");
            map.put("data", member);
        }catch (Exception e) {
            e.printStackTrace();
            map.put("code", e.getClass().getSimpleName());
            map.put("message", e.getMessage());
        }
        return map;
    }


    /**
     * 远程调用我们需要的book服务里面对应的操作
     * @param bid
     * @return
     */
    @GetMapping("/test")
    @ResponseBody
    public String test(Long bid) {
        //在这里我们使用SpringCloud内置的RestTemplate对象进行远程调用
        RestTemplate restTemplate = new RestTemplate();   //这里先new一个RestTemplate对象
        String json = restTemplate.getForObject("http://localhost:8100/info?bid=" + bid, String.class);
        System.out.println(json);
        return json;
    }
}

把所有服务开启,在浏览器对member项目做单体应用测试:输入地址:http://localhost:8088/test?bid=1具体的返回如下图所示

其实我们发现我们访问的本来是member服务里面的请求但是调用的却是book服务里面的数据  

但是有个问题我们要说下就是我们根据RestTemplate获得的数据地址时被写死了,所以不推荐使用这种方式,那么我们就要换一种方式进行操作

RestTemplate restTemplate = new RestTemplate();   //这里先new一个RestTemplate对象
String json = restTemplate.getForObject("http://localhost:8100/info?bid=" + bid, String.class);

我们在这里采用Ribben进行客户端负载均衡,那么我们要改写上面的代码:

//注入负载均衡客户端,这里Ribbon的核心组件
@Autowired
private LoadBalancerClient loadBalancerClient;
/**
 * 远程调用我们需要的book服务里面对应的操作
 * @param bid
 * @return
 */
@GetMapping("/test")
@ResponseBody
public String test(Long bid) {
    //在这里我们使用SpringCloud内置的RestTemplate对象进行远程调用
    //RestTemplate restTemplate = new RestTemplate();   //这里先new一个RestTemplate对象
    //String json = restTemplate.getForObject("http://localhost:8100/info?bid=" + bid, String.class);
    //System.out.println(json);

    //不推荐使用RestTemplate因为被写死了远程调用的地址
    //推荐使用Ribbon进行负载均衡远程调用
    RestTemplate restTemplate = new RestTemplate();
    //获得服务列表
    ServiceInstance instance = loadBalancerClient.choose("book");//在Erueak服务中获得book服务的名字并找到该服务
    String host = instance.getHost();   //获得主机端口号
    int port = instance.getPort();    //获得端口号
    //通过RestTemplate做远程调用
    String json = restTemplate.getForObject("http://" + host + ":" + port + "/info?bid=" + bid, String.class);
    return json;
}

然后输入地址进行测试http://localhost:8088/test?bid=1

 我们来看下我们使用Ribbon也可以完成对服务的请求的操作,而且我们只需要拿到某个服务的服务名称可端口就可以直接访问那个服务了

客户端负载均衡Ribbon执行流程

我们知道Ribbon是负载均衡的客户端,那么他也是具备负载均特性的,所以我们做个测试,先把book项目按照8100端口进行启动,然后回到我们的git里面进行对配置中心的设置把配置中心的端口从8100改成8101再次进行做一个8101服务启动看看我们Ribbon是否能够执行负载均衡的操作,我呢可以debug进行测试。答案是肯定的,这就是Ribbon的作用它会根据我们在Eureka中提供的服务器列表进行轮询操作,那么这个就是Ribbon的核心技术负载均衡。

但是我们看到上面虽然实现了负载均衡的操作,对于代码的角度来说还是比较难看的,那么我么要改写代码,让他的操作更为简洁,如下所示

我们要在member项目上进行改写

首先我们打开member项目的主启动类

package com.laosan.member;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class MemberApplication {
   public static void main(String[] args) {
      SpringApplication.run(MemberApplication.class, args);
   }

    /**
     * 注入一个RestTemplate
     * @return
     */
   @Bean
   @LoadBalanced   //对RestTemplate对象进行负载均衡操作
   public RestTemplate  getRestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate;
    }
}

然后简化member项目中的Controller方法的操作

//在这里注入我们RestTemplate
@Autowired
private RestTemplate restTemplate;

/**
 * 远程调用我们需要的book服务里面对应的操作
 * @param bid
 * @return
 */
@GetMapping("/test")
@ResponseBody
public String test(Long bid) {
    //在这里我们使用SpringCloud内置的RestTemplate对象进行远程调用
    //RestTemplate restTemplate = new RestTemplate();   //这里先new一个RestTemplate对象
    //String json = restTemplate.getForObject("http://localhost:8100/info?bid=" + bid, String.class);
    //System.out.println(json);

    //不推荐使用RestTemplate因为被写死了远程调用的地址
    //推荐使用Ribbon进行负载均衡远程调用
    //RestTemplate restTemplate = new RestTemplate();
    //获得服务列表
    //ServiceInstance instance = loadBalancerClient.choose("book");//在Erueak中获得book服务的名字并找到该服务
    //String host = instance.getHost();   //获得主机端口号
    //int port = instance.getPort();    //获得端口号
    //通过RestTemplate做远程调用
    //String json = restTemplate.getForObject("http://" + host + ":" + port + "/info?bid=" + bid, String.class);

    //这里直接通过RestTemplate进行操作即可
    String json = restTemplate.getForObject("http://book/info?bid="+bid, String.class);
    return json;
}

其实我们来看代码变的极为简单

输入地址进行测试即可:

主启动类上:

@Autowired
private  RestTemplate restTemplate;

@RequestMapping("/test")
public  String test(Long bid){
    /*//创建一个对象
    RestTemplate restTemplate=new RestTemplate();    //Spring对httpclient 进行了封装
    String str = restTemplate.getForObject("http://localhost:8006/info?bid=" + bid, String.class);
    return str;*/
    //不推荐使用RestTemplate因为被写死了远程调用的地址
    //推荐使用Ribbon进行负载均衡远程调用
   /* RestTemplate restTemplate = new RestTemplate();
    //获得服务列表
    ServiceInstance instance = loadBalancerClient.choose("book");//在Erueak服务中获得book服务的名字并找到该服务
    String host = instance.getHost();   //获得主机端口号
    int port = instance.getPort();    //获得端口号
    //通过RestTemplate做远程调用
    String json = restTemplate.getForObject("http://" + host + ":" + port + "/info?bid=" + bid, String.class);
    return json;*/
String str = restTemplate.getForObject("http://book/info?bid=" + bid, String.class);
    return  str;

}

服务间的通信Feign :

 

下面让我们来改造member项目,第一步引入Feign的依赖:

<!--feign的相关依赖-->
<!--feign的相关依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

然后在member项目的启动类中添加一个注解用来启动feign

package com.laosan.member;

 

@SpringBootApplication
@EnableFeignClients        //开启feign客户端
public class MemberApplication {
   public static void main(String[] args) {
      SpringApplication.run(MemberApplication.class, args);
   }
   @Bean
    @LoadBalanced   //对RestTemplate对象进行负载均衡操作
   public RestTemplate  getRestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate;
    }
}

我们下面开始操作fegin,首先在member项目中我们创建一个client包在该包下我们来进行操作:

package com.laosan.member.client;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name="book")   //这里book是Eureka中book服务的名字,这里说明我们要调用book微服的客户端
public interface BookClient {
    @GetMapping("/info")   //请求,这里的请求是和book服务里面的请求保持一致的
    //@RequestParam("bid") 是绑定传递过去参数的,get请求使用@RequestParam
    public String getInfo(@RequestParam("bid") Long bid);
}

我们在member项目的Controller中根据fegin的操作从新定义一个方法

 

@Autowired
private BookFeignClient bookFeignClient;

@RequestMapping("/test1")
public  String test1(Long bid){
    String str= bookFeignClient.info(bid);
    return str;
}

输入地址进行单体member项目的测试:http://localhost:8088/test1?bid=1

 

这里对于feign操作请求的时候如果是post这里有个细节我么要知道,如下所示:

//这里如果是post请求我们在绑定参数的时候必须使用@RequestBody
@PostMapping("/aa")
public String aa(@RequestBody String aa);

格式化book服务中返回的数据,来看下图

 根据上面的通过feign的方法我们知道我们返回的数据是一个字符串,但是我们知道我们返回的数据其实是有对象的数据在里面的如我们data的数据,那么我们要对整体返回的数据进行格式化,如下面操作

首先在Member项目中我们创建一个vo包,并创建一个类:

package com.laosan.member.vo;

import lombok.Data;

import java.io.Serializable;

/**
 * 格式化数据的封装类
 */
@Data
public class ResultVo<T> implements Serializable {
    private String code;
    private String message;
    private T data;
}

在member项目中创建dto包并创建一个类用于封装从服务端传递过来的对象:

这个对象里面的数据要和json字符串里面的data数据保持一致

package com.laosan.member.dto;

import lombok.Data;

import java.io.Serializable;

/**
 * 封装book的类
 */
@Data
public class BookDTO implements Serializable {
    private Long bid;
    private String sn;
    private String name;
    private String author;
    private String publishing;
    private Float bprice;
    private Float sprice;
    private String btype;
    private Integer stock;
}

对feign的操作接口进行修改,如下所示:

@FeignClient(name="book")   //这里book是Eureka中book服务的名字,这里说明我们要调用book微服的客户端
public interface BookClient {
    @GetMapping("/info")   //请求,这里的请求是和book服务里面的请求保持一致的
    //@RequestParam("bid") 是绑定传递过去参数的,get请求使用@RequestParam
    public ResultVo<BookDTO> getInfo(@RequestParam("bid") Long bid);
}

然后对member项目中的controller对应的方法进行修改:

@Autowired
private BookClient bookClient;

@GetMapping("/test1")
@ResponseBody
public String test1(Long bid) {
    ResultVo<BookDTO> resultVo = bookClient.getInfo(bid);
    return resultVo.getData().getName();
}

最后进行测试即可:

 最后强调个东西Feign默认就是支持Ribbon的负载均衡策略

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/563744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在 Kubernetes 上实现高速应用交付

原文作者&#xff1a;NGINX 原文链接&#xff1a;在 Kubernetes 上实现高速应用交付 转载来源&#xff1a;NGINX 官方网站 NGINX 唯一中文官方社区 &#xff0c;尽在 nginx.org.cn 运行于 Kubernetes 之上的应用需要一个经过验证的生产级应用交付解决方案。NGINX Ingress Cont…

边缘计算AI硬件智能分析网关V1版的接入流程与使用步骤

我们的AI边缘计算网关硬件——智能分析网关目前有两个版本&#xff1a;V1版与V2版&#xff0c;两个版本都能实现对监控视频的智能识别和分析&#xff0c;支持抓拍、记录、告警等&#xff0c;在AI算法的种类上和视频接入上&#xff0c;两个版本存在些许的区别。V1的基础算法有人…

【ChatGPT】《吴恩达 x OpenAI Prompt Engineering教程中文笔记》- 知识点目录

《吴恩达 x OpenAI Prompt Engineering教程中文笔记》 &#x1f433; 在开始编写提示词之前的一些设置 不同的temperature会影响模型的理性和想象力&#xff0c;这里告诉我们&#xff1a; Low&#xff1a;例如GPT4&#xff0c;更加适合确定性的问答任务Hight&#xff1a;例如…

non-protected broadcast场景分析及解决

non-protected broadcast场景分析及解决 在两个app之间互相送消息使用BroadcastReceiver&#xff0c;有时在运行过程中在logcat工具中会发现大片的飘红消息。 要消除这些错误信息&#xff0c;需要在广播的 Sender 和 Receiver 做部分的修改。 错误信息分析 由于 发送端 的 M…

忆享聚焦|ChatGPT、AI、网络数字、游戏……近期热点资讯一览

“忆享聚焦”栏目第十四期来啦&#xff01;本栏目汇集近期互联网最新资讯&#xff0c;聚焦前沿科技&#xff0c;关注行业发展动态&#xff0c;筛选高质量讯息&#xff0c;拓宽用户视野&#xff0c;让您以最低的时间成本获取最有价值的行业资讯。 目录 行业资讯 1.科技部部长王志…

上海亚商投顾:沪指跌1.28%失守年线 大金融板块集体走弱

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日继续调整&#xff0c;沪指超1%逼近3200点&#xff0c;尾盘失守年线&#xff0c;创业板指较为抗跌。大…

你收藏了那些实用工具类网站?

今天来给大家分享几个众多网友们推荐的&#xff0c;宝藏工具类网站 uIGradients https://uigradients.com/#Flickr 专业的渐变色配色工具网站&#xff0c;配色什么的非常全&#xff0c;也可以按照自己的想法来选择搭配&#xff0c;还能直接获得对应渐变配色的CSS代码&#xff…

水表自动抄表系统有什么功能

水表自动抄表系统是一种新型的智能化管理系统&#xff0c;它可以自动采集水表的数据&#xff0c;并且实时上传到管理平台&#xff0c;实现了水表的实时监测和管理。该系统具有以下几个主要功能&#xff1a; 1.自动抄表功能 水表自动抄表系统可以实现自动采集水表的数据&#x…

【学习笔记】Windows 下线程同步之互斥锁

目录 前言环境简介相关函数CreateMutex Wait 函数ReleaseMutexCloseHandle 其他互斥锁的名字未命名互斥锁的同步互斥锁的意外终止临界区对象 参考 前言 本文所涉及的同步主要描述在 Windows 环境下的机制&#xff0c;和 Linux 中的同步机制有一定的联系&#xff0c;但注意并不…

小猫踩球-第14届蓝桥杯省赛Scratch中级组真题第2题

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第137讲。 小猫踩球&#xff0c;本题是2023年5月7日举行的第14届蓝桥杯省赛Scratch图形化编程中级组真题第2题&#xf…

智慧档案馆一体化监控系统设计所需要的10条依据

1.科学性 本项目目标定位为&#xff1a;以科学技术为基础&#xff0c;依靠先进的设备和优越的设计理念、科学客观的管理&#xff0c;利用信息化管理及相关最新技术&#xff0c;将库房实际环境与存储技术、计算机技术、无线自动控制技术、通讯与信息处理技术等先进技术相结合&a…

Python appium搭建app自动化测试环境

目录 前言 App自动化环境安装 安装安卓开发工具 安装模拟器 前言 appium做app自动化测试&#xff0c;环境搭建是比较麻烦的。 也是很多初学者在学习app自动化之时&#xff0c;花很多时间都难跨越的坎。 但没有成功的环境&#xff0c;就没有办法继续后续的使用。 在app自…

面试技术点

一、对热修复、插件化、模块化、组件化有一定研究。 1、模块化 将共享部分或业务模块抽取出来形成独立module。 2、组件化 基于模块化&#xff0c;核心思想是角色的转换&#xff0c;在打包时是library&#xff0c;分离独立的业务组件如微信朋友圈。 3、热修复和插件化种类、…

在Kaggle上使用Stable Diffusion进行AI绘图

前言 因为使用Stable Diffusion进行AI绘图需要GPU&#xff0c;这让其应用得到了限制本文介绍如何在Kaggle中部署Stable Diffusion&#xff0c;并使用免费的P100 GPU进行推理&#xff08;每周可免费使用30小时&#xff09;&#xff0c;部署好后可以在任意移动端使用。本项目在s…

2023全球最佳医院榜单及简要介绍

作为医学类的访问学者、博士后及联合培养博士们&#xff0c;都希望到世界知名医院进行临床研修交流及科研学习。2023 年世界最佳医院排行榜的发布为申请者提供了目标平台&#xff0c;现知识人网小编整理刊出。 近期&#xff0c;《新闻周刊》和全球数据公司 Statista 推出了2023…

拿了7家大厂offer后,整理出来的笔记.....

我第一次接触自动化是在2016年。那时刚毕业一年有余&#xff0c;组内一直做手工功能测试&#xff0c;大概在2018年9月&#xff0c;部门领导要求测试组引入自动化。组内之前从没有开展过任何自动化&#xff0c;测试主管安排了一个刚入职不久的研究生同事去研究。 当时自己内心还…

UniApp原生插件制作

参考1&#xff1a;UniApp官网-原生插件开发 参考2&#xff1a;uniapp Android 原生插件开发 一、下载安装Android Studio 本部分不在赘述 二、下载UniApp离线SDK 下载地址&#xff1a;Android 离线SDK - 正式版 | uni小程序SDK 三、解压下载文件&#xff0c;并导入Androi…

蓝精灵协会:如何将传统 IP 融入 Web3

作者&#xff1a;Cedric Hervet&#xff0c;联合创始人&#xff0c;创意总监 我和许多项目合作过&#xff0c;并且担任了近 30 年的艺术总监和创意总监。我的方法一直是创造同质化的宇宙&#xff0c;把观众带入并使他们产生梦想。但我也曾系统地寻找过那份额外的感动&#xff1…

微服务解码:揭示API的优势挑战与最佳实践

在当今快节奏的软件开发环境中&#xff0c;微服务已成为一种流行的架构模式。但微服务到底是什么&#xff1f;简而言之&#xff0c;微服务是一种将应用程序构建为松耦合、细粒度服务集合的方式&#xff0c;这些服务通过轻量级协议进行通信。这种架构风格使团队能够独立开发和部…

el-upload上传图片成功,详情页回显base64格式的图片

上传图片&#xff0c;并传给后端图片格式是base64。在详情页需要回显图片在el-upload上&#xff0c;我们发现官网里图片回显时&#xff0c;文件数组里要配置好name和url,如下图&#xff1a; 当我们需要回显base64格式的图片时&#xff0c;我们需要将要回显的文件数组处理成id和…