Spring Cloud Alibaba微服务系列-服务调用Op
2021-05-28 本文已影响0人
小虎哥的技术博客
一、前言
一个项目拆分成多个服务之后,多个服务之间肯定会相互调用,如购买请求需要调用商品服务减库存、调用订单服务创建订单、调用积分服务增加积分等。
Open Feign通过接口的方式来调用服务,对于开发者来说非常友好。
准备工作:数据库创建下面这张表
- id long类型
- name String类型
- number int类型
CREATE TABLE `product` (
`id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT '主键id',
`name` VARCHAR(20) NOT NULL DEFAULT '' COMMENT '商品名称' COLLATE 'utf8mb4_general_ci',
`number` INT(11) NOT NULL DEFAULT '0' COMMENT '商品数量',
PRIMARY KEY (`id`) USING BTREE
)
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
;
然后随便加上一条商品数据
二、目录结构
QQ截图20210520144438.png-
parent
版本号管理 -
consumer
服务消费者 -
product
商品服务 -
product-api
商品服务接口
后面的操作就是consumer
服务调用product
服务
三、parent
模块
parent
模块是做版本号管理的,里面只有pom.xml
文件
3.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.llh</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
<name>parent</name>
<description>parent description</description>
<packaging>pom</packaging>
<properties>
<spring-cloud.version>2020.0.2</spring-cloud.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
<mybatis.version>2.1.4</mybatis.version>
<mybatis-plus.version>3.4.2</mybatis-plus.version>
</properties>
<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>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
四、product
商品模块(服务提供者)
QQ截图20210520150327.png
4.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.llh</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product</artifactId>
<version>1.0.0</version>
<name>product</name>
<description>product description</description>
<dependencies>
<dependency>
<groupId>com.llh</groupId>
<artifactId>product-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
- 引入了
product-api
模块 - 引入了
spring-cloud-starter-openfeign
依赖
4.2 application.properties
# 应用名称
spring.application.name=product
server.port=7777
# nacos服务注册相关
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
spring.cloud.nacos.discovery.server-addr=http://localhost:8848
spring.cloud.nacos.discovery.namespace=83e9d384-d49e-4f40-84bf-c25612883dcc
# 数据库相关
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false
spring.datasource.username=root
spring.datasource.password=0320
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# mybatis相关
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
4.3 ProductApplication
类
package com.llh.product;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author 小虎哥的技术博客
*/
@SpringBootApplication
@MapperScan(value = "com.llh.product.mapper")
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
}
4.4 ProductController
类
package com.llh.product.controller;
import com.llh.product.service.ProductService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author 小虎哥的技术博客
*/
@RestController
@RequestMapping("/product")
public class ProductController {
@Resource
private ProductService productService;
@GetMapping("/decrease/{productId}/{number}")
public Boolean decrease(@PathVariable Long productId, @PathVariable Integer number) {
return productService.decrease(productId, number);
}
}
4.5 ProductServiceImpl
package com.llh.product.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.llh.product.api.entity.Product;
import com.llh.product.mapper.ProductMapper;
import com.llh.product.service.ProductService;
import org.springframework.stereotype.Service;
/**
* @author 小虎哥的技术博客
*/
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
@Override
public Boolean decrease(Long productId, Integer number) {
Product product = getById(productId);
// 判断商品数量够不够
if ((product.getNumber() - number) > 0) {
// 商品数量减少
product.setNumber(product.getNumber() - number);
return updateById(product);
} else {
return false;
}
}
}
这里就是减商品库存,先判断商品数量够不够,如果够了就减。
五、product-api
模块
QQ截图20210520150417.png
可以看到entity被放在了Api模块,因为entity类很多服务都会用到,所以单独放出来。
5.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.llh</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-api</artifactId>
<version>1.0.0</version>
<name>product-api</name>
<description>product api description</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
5.2 Product
类
public class Product {
private Long id;
private String name;
private Integer number;
// 省略setter getter
}
5.3 ProductApi
类
package com.llh.product.api.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @author 小虎哥的技术博客
*/
@FeignClient(name = "product")
public interface ProductApi {
/**
* 减少商品数量
*
* @param productId 商品id
* @param number 数量
* @return 是否成功
*/
@GetMapping("/product/decrease/{productId}/{number}")
Boolean decrease(@PathVariable Long productId, @PathVariable Integer number);
}
关键
- 通过
@FeignClient(name = "product")
这个注解来找到服务,product
就是服务名称。 - 服务调用方调用
decrease
方法, Open Feign 就会调用 服务名为product
的@GetMapping("/product/decrease/{productId}/{number}")
接口。
六、consumer
消费者模块(服务调用方)
QQ截图20210520151205.png
6.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.llh</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>consumer</artifactId>
<version>1.0.0</version>
<name>consumer</name>
<description>consumer description</description>
<dependencies>
<dependency>
<groupId>com.llh</groupId>
<artifactId>product-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
</dependencies>
</project>
-
spring-cloud-starter-openfeign
和spring-cloud-loadbalancer
这两个依赖。
6.2 application.properties
# 应用相关
spring.application.name=consumer
server.port=8888
# nacos服务注册相关
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
spring.cloud.nacos.discovery.server-addr=http://localhost:8848
spring.cloud.nacos.discovery.namespace=83e9d384-d49e-4f40-84bf-c25612883dcc
6.3 ConsumerApplication
package com.llh.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author 小虎哥的技术博客
*/
@SpringBootApplication
@EnableFeignClients(basePackages = "com.llh.*")
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
- 注意:要加上
EnableFeignClients
注解,扫描@FeignClient
,就是实例化Feign 客户端
6.4 ConsumerController
package com.llh.consumer.controller;
import com.llh.consumer.service.ConsumerService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author 小虎哥的技术博客
*/
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Resource
private ConsumerService consumerService;
@GetMapping("/buy/{productId}/{number}")
public Boolean buy(@PathVariable Long productId, @PathVariable Integer number) {
return consumerService.buy(productId, number);
}
}
这里模拟购买商品/consumer/buy/{productId}/{number}
6.4 ConsumerServiceImpl
package com.llh.consumer.service.impl;
import com.llh.consumer.service.ConsumerService;
import com.llh.product.api.feign.ProductApi;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author 小虎哥的技术博客
*/
@Service
public class ConsumerServiceImpl implements ConsumerService {
@Resource
private ProductApi productApi;
@Override
public Boolean buy(Long productId, Integer number) {
productApi.decrease(productId, number);
return true;
}
}
- 说明:
productApi.decrease
是不是就像调用内部的方法一样去调用远程服务接口,非常简单。
6.5 测试
http://localhost:8888/consumer/buy/1/1
请求接口,可以看到商品id为1的商品数量减少了1个。
调用路径:consumer-->product-api-->product
七、结语
生产环境中一个服务会部署多个实例,Open Feign调用会随机选择一个实例。当然负载均衡的规则可以配置轮询、随机、空闲等。
源码地址:https://github.com/tigerleeli/xiaohuge-blog/tree/master/spring-cloud-alibaba-feign
这里代码粘贴了很多(略显啰嗦),把很多配置文件都放在文章上,因为个人觉得对于刚接触的人来说有时候就是因为一两个包或者配置文件没用弄好而卡很久。不知道大家是喜欢简单,只写关键代码。还是喜欢全面一点,不漏任何细节,像我这篇文章这样的。
同步微信公众号:小虎哥的技术博客