Spring Cloud微服务架构从入门到会用(三)—服务间调用Feign

Stella981
• 阅读 376

微服务最重要的一个功能是服务间调用,各个服务互相依赖。比如电商系统有订单服务,有库存服务。在我们购买一件商品的时候,需要生成订单和减库存。这里我们就要用到服务间调用Feign。

Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用。

接下来我们新建两个module,一个app-order,一个app-storage;app-order作为调用方,app-storage作为被调用方。使用mybatis-plus作为数据处理框架。使用lombok简化代码(idea需要按照lombok插件,否则会报错)

1. 创建app-storage

1.1 修改app-storage下的pom.xml文件
<properties>   <java.version>1.8</java.version>   <spring-cloud.version>Hoxton.SR1</spring-cloud.version></properties><dependencies>   <dependency>       <groupId>org.springframework.boot</groupId>       <artifactId>spring-boot-starter-web</artifactId>   </dependency>    <!-- eureka-client -->   <dependency>       <groupId>org.springframework.cloud</groupId>       <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>   </dependency>   <!-- feign -->   <dependency>       <groupId>org.springframework.cloud</groupId>       <artifactId>spring-cloud-starter-openfeign</artifactId>   </dependency>   <!--    mybatis-plus    -->   <dependency>       <groupId>com.baomidou</groupId>       <artifactId>mybatis-plus-boot-starter</artifactId>       <version>3.3.1.tmp</version>   </dependency>   <dependency>       <groupId>mysql</groupId>       <artifactId>mysql-connector-java</artifactId>       <scope>runtime</scope>   </dependency>   <dependency>       <groupId>org.projectlombok</groupId>       <artifactId>lombok</artifactId>       <optional>true</optional>   </dependency>   <dependency>       <groupId>org.springframework.boot</groupId>       <artifactId>spring-boot-starter-test</artifactId>       <scope>test</scope>       <exclusions>           <exclusion>               <groupId>org.junit.vintage</groupId>               <artifactId>junit-vintage-engine</artifactId>           </exclusion>       </exclusions>   </dependency></dependencies><dependencyManagement>   <dependencies>       <dependency>           <groupId>org.springframework.cloud</groupId>           <artifactId>spring-cloud-dependencies</artifactId>           <version>${spring-cloud.version}</version>           <type>pom</type>           <scope>import</scope>       </dependency>   </dependencies></dependencyManagement>
1.2 修改配置
# 设置端口号server.port=9920# 设置服务名称spring.application.name=app-storage# 设置eurekaeureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/eureka.instance.instance-id=${spring.application.name}:${server.port}# 数据源配置spring.datasource.url=jdbc:mysql://localhost:3306/storage?allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=truespring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.username=rootspring.datasource.password=root
1.3 创建表,预制数据
CREATE TABLE `tb_storage` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `commodity_code` varchar(255) DEFAULT NULL,  `count` int(11) DEFAULT 0,  PRIMARY KEY (`id`),  UNIQUE KEY (`commodity_code`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

预制数据

INSERT INTO `storage`(`id`, `commodity_code`, `count`) VALUES (1, 'product-1', 9999999);
1.4 修改启动类
@SpringBootApplication@EnableEurekaClient  // 开启eureka客户端模式@MapperScan("com.ipp.springcloud.appstorage.mapper") // mybatis扫描public class AppOrderApplication {    public static void main(String[] args) {        SpringApplication.run(AppOrderApplication.class, args);    }}
1.5 创建storage表对应的entity,mapper,service,controller

可以用mybatis-plus代码生成插件去生成以上代码,篇幅问题不在此处做详细展示,详细内容请查看git仓库。

1.6 创建一个供app-order调用的减库存接口

controller

/**     * 减库存     * @param commodityCode 商品代码     * @param count 数量     * @return     */    @RequestMapping(path = "/deduct")    public Boolean deduct(String commodityCode, Integer count) {        storageService.deduct(commodityCode, count);        return true;    }

service

@Override    public void deduct(String commodityCode, int count) {        QueryWrapper<Storage> wrapper = new QueryWrapper<>();        wrapper.setEntity(new Storage().setCommodityCode(commodityCode));        Storage storage = baseMapper.selectOne(wrapper);        storage.setCount(storage.getCount() - count);        baseMapper.updateById(storage);    }

2. 创建app-order

2.1 修改app-order下的pom.xml文件

内容与app-storage一致

2.2 修改配置
# 设置端口号server.port=9910# 设置服务名称spring.application.name=app-order# 设置eurekaeureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/eureka.instance.instance-id=${spring.application.name}:${server.port}# 数据源配置spring.datasource.url=jdbc:mysql://localhost:3306/order?allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=truespring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.username=rootspring.datasource.password=root
2.3 创建表
CREATE TABLE `tb_order` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `user_id` varchar(255) DEFAULT NULL,  `commodity_code` varchar(255) DEFAULT NULL,  `count` int(11) DEFAULT 0,  `money` int(11) DEFAULT 0,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.4 修改启动类
@SpringBootApplication@EnableEurekaClient  // 开启eureka客户端模式@EnableFeignClients //开启feign请求@MapperScan("com.ipp.springcloud.apporder.mapper") // mybatis扫描public class AppOrderApplication {    public static void main(String[] args) {        SpringApplication.run(AppOrderApplication.class, args);    }}
2.5 创建表order表对应的entity,mapper,service,controller

可以用mybatis-plus代码生成插件去生成以上代码,篇幅问题不在此处做详细展示,详细内容请查看git仓库。

2.6 创建feign调用接口
@FeignClient(name = "APP-STORAGE")public interface StorageFeignService {    /**     * 减库存     * @param commodityCode     * @param count     * @return     */    @GetMapping("storage/deduct")    Boolean deduct(@RequestParam("commodityCode") String commodityCode, @RequestParam("count") Integer count);}

这里的@FeignClient 中的name写的是app-storage服务的服务名称(也就是注册到eureka中的服务名称)

下面声明的deduct方法对应app-storage服务中的deduct接口

2.7 创建下订单的接口

controller

 @RequestMapping("/placeOrder/commit")    public Boolean placeOrderCommit() {        orderServiceImpl.placeOrder("1", "product-1", 1);        return true;    }

service

@Autowiredprivate StorageFeignService storageFeignService;@Overridepublic void placeOrder(String userId, String commodityCode, Integer count) {     BigDecimal orderMoney = new BigDecimal(count).multiply(new BigDecimal(5));     Order order = new Order()             .setUserId(userId)             .setCommodityCode(commodityCode)             .setCount(count)             .setMoney(orderMoney);     baseMapper.insert(order);     storageFeignService.deduct(commodityCode, count);}

3. 启动服务验证

依次启动server-eureka,app-storage,app-order

4. 验证接口

在浏览器中访问 http://127.0.0.1:9910/order/placeOrder/commit , 分别查看order表和storage表。是否生成了订单和减了库存

本文分享自微信公众号 - 自增程序员(javaipp)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
lzy lzy
1年前
RPC框架手撕之路---初步了解RPC(小白勿喷)
博主小菜鸡一只,目前研二上学期,之前对rpc框架了解不多,想课余时间丰富一下自己的java知识,通过该系列博客勉励自己,内容对大佬来说可能过于简单,还请轻喷,谢谢。初步理解:RPC是指远程过程调用,通过网络从远程计算机程序上请求服务,此框架需要做到的是——使得客户端直接调用服务端的方法就像调用本地方法一样简单,所以一般不涉及到解析和封装HTTP请求和相应的
Wesley13 Wesley13
1年前
Java 调用RESTful接口的几种方式
前端一般通过Ajax来调用,后端调用的方式还是挺多的,比如HttpURLConnection,HttpClient,Spring的RestTemplate服务端代码如下:服务端接口请求的URL:http://localhost:8080/rest/user/getUser/xiaoming/18(https://www.oschina.net/a
Stella981 Stella981
1年前
Linkis架构解析系列(一)——Linkis RPC架构解析
“为了提升Linkis的高并发能力,Linkis基于微服务架构,在Feign的基础之上,实现了一套自己的底层RPC通信方案,用以提升微服务间的通信性能和并发能力。”基于Feign的微服务之间HTTP接口调用,只能满足简单的A微服务实例根据简单的规则随机访问B微服务之中的某个服务实例,而这个B微服务实例如果想异步回传信
Stella981 Stella981
1年前
Nacos(三):Nacos与OpenFeign的对接使用
前言上篇文章中,简单介绍了如何在SpringCloud项目中接入Nacos作为注册中心,其中服务消费者是通过RestTemplateRibbon的方式来进行服务调用的。实际上在日常项目中服务间调用大都用的是OpenFeign,OpenFeign自身整合了Ribbon和Hystrix,为服务调用提供了更优雅的方式那么接入了Naco
Wesley13 Wesley13
1年前
spring feign http客户端连接池配置以及spring zuul http客户端连接池配置解析
背景Feign和网关Zuul的RPC调用,实际上都是HTTP请求。HTTP请求,如果不配置好HTTP连接池参数的话,会影响性能,或者造成堆积阻塞,对于其中一个微服务的调用影响到其他微服务的调用。源代码类比解析本文基于SpringCloudDalston.SR4,但是基本思路上,这块比较稳定,不稳定的是Feign本身Htt
Easter79 Easter79
1年前
SpringCloud学习笔记(四)之Ribbon负载均衡
    在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于httprestful的。Springcloud有两种服务调用方式,一种是ribbonrestTemplate,另一种是feign。简介是基于NetflixRibbon实现的一套客户端负载均衡的工具。简单的说,Ribbon是
Easter79 Easter79
1年前
SpringCloud的限流、降级和熔断——Hystrix
!(https://oscimg.oschina.net/oscnet/updb144b1538f24c2488b01c4e66a45d48038.JPEG)一、前言分布式系统环境中,服务间类似依赖非常常见,一个业余调用通常依赖多个基础服务。如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,
Easter79 Easter79
1年前
SpringCloud介绍
自己通俗的理解只能是Http协议调用,Dubbo可以支持多种协议就是RPC远程调用就是提供服务注册,服务发现,断路器,网关系统和自动配置的工具,底层采用http协议实现采用Eureka注册中Ribbon实现负载均衡Feignhttp协议调用工具Hystrix断路器Zuul网关系统就是把API服务通过注册中心
Easter79 Easter79
1年前
SpringCloud开发学习总结(三)—— 服务治理Eureka
 在最初开始构建微服务系统的时候可能服务并不多,我们可以通过做一些静态配置来完成服务的调用。比如,有两个服务A和B,其中服务A需要调用服务B来完成一个业务操作时,为了实现服务B的高可用,不论采用服务端负载均衡还是客户端负载均衡,都需要手工维护服务B的具体实例清单。但是随着业务的发展,系统功能越来越复杂,相应的微服务应用也不断增加,我们的静态配置会变得越来越
Stella981 Stella981
1年前
Dubbo之服务调用
概述Dubbo能够像调用本地服务一样调用远程服务,是依赖于Dubbo的代理机制。业务系统调用的服务方法,使用代理类,代理类里隐藏了远程通信的功能。代理对象会代理到InvokerInvocationHandler上,再调用它属性Invoker_invoke_()方法。这个Invoker是服务引用的过程中由Protocol创建的。比如
Stella981 Stella981
1年前
Hystrix原理与实战(文章略长)
背景分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应。!(https://stati