微服务-注册中心、配置中心、网关
组件选择
参考:官方
注册中心:SpringCloud Alibaba Nacos
配置中心:SpringCloud Alibaba Nacos
负载均衡:SpringCloud Ribbon
声明式HTTP客户端:SpringCloud Feign ——调用远程服务
负载均衡:SpringCloud Ribbon —— feign中已经整合,无需显示引用
服务容错:SpringCloud Alibaba Sentinel ——限流、降级、熔断
API网关:SpringCloud Gateway ——webflux 编程模式
调用链路监控:SpringCloud Sleuth
分布式事务:SpringCloud Alibaba Seata ——原Fescar
下载 Nacos Server
下载地址:Github Release 由上面版本选择可知:当前对应 Nacos 版本为1.2.1
下载对应系统的tar包(Linux)或者zip包(Windows),解压后运行bin目录下的可执行文件即可运行Nacos
引入Nacos作为注册中心
1. pom文件引入依赖
common模块 ```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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<artifactId>mall</artifactId>
<groupId>groupId</groupId>
<version>1.0-SNAPSHOT</version>
4.0.0 mall-common 每一个微服务公共的依赖,bean,工具类等 <!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.12</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!-- 导入mysql驱动 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- 服务注册/发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.1.8.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.0-M1</version>
<scope>test</scope>
</dependency>
<!-- 配置中心来做配置管理-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- coupon模块
```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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ht.mall</groupId>
<artifactId>gulimall-coupon</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mall-coupon</name>
<description>商城-优惠卷服务</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>groupId</groupId>
<artifactId>mall-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.0-M1</version>
<scope>test</scope>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. yaml文件增加配置
在 coupon 中的application.yml 配置文件中配置 Nacos Server 地址和微服务名称
spring:
application:
name: mall-coupon
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.1.103:3306/mall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
cloud:
nacos:
discovery:
server-addr: localhost:8848
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto
server:
port: 7000
3. 主启动类增加注解
使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
@MapperScan("com.ht.mall.product.dao")
@SpringBootApplication
@EnableDiscoveryClient
public class MallCouponApplication {
public static void main(String[] args) {
SpringApplication.run(MallCouponApplication.class, args);
}
}
此时,启动Nacos,运行主启动类启动服务后,在浏览器打开配置文件中的地址:localhost:8848/nacos (账号密码:nacos/nacos)中就可以看到当前服务已经注册到 Nacos 服务列表中
引入Feign远程服务调用
测试member和coupon的远程调用
想要获取当前会员领取到的所有优惠券。先去注册中心找优惠券服务, 注册中心调一台优惠券服务器给会员,会员服务器发送请求给这台优 惠券服务器,然后对方响应。
Feign与注册中心
spring cloud feign
声明式远程调用
feign是一个声明式的HTTP客户端,他的目的就是让远程调用更加简单。
给远程服务发的是HTTP请求。
会员服务想要远程调用优惠券服务,只需要给会员服务里引入openfeign依赖,他就有了远程调用其他服务的能力。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在coupon中修改如下的内容
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
@RequestMapping("/member/list")
public R membercoupons(){ //全系统的所有返回都返回R
// 应该去数据库查用户对于的优惠券,但这个我们简化了,不去数据库查了,构造了一个优惠券给他返回
CouponEntity couponEntity = new CouponEntity();
couponEntity.setCouponName("满100减10");//优惠券的名字
return R.ok().put("coupons",Arrays.asList(couponEntity));
}
这样我们准备好了优惠券的调用内容 在member的配置类上加注解@EnableFeignClients(basePackages=”com.ht.mall.member.feign”), 告诉spring这里面是一个远程调用客户端,member要调用的接口
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages="com.ht.mall.member.feign")
public class MallMemberApplication {
public static void main(String[] args) {
SpringApplication.run(MallMemberApplication .class, args);
}
}
调用刚才写的优惠券的功能
复制函数部分,在member的com.ht.mall.member.feign包下新建接口:
/**
* 告诉spring cloud这个接口是一个远程客户端
*/
@FeignClient("mall-coupon")
public interface CouponFeignService {
/**
* 调用coupon服务,再去调用coupon服务/coupon/coupon/member/list对应的方法
* @return 得到一个R对象
*/
@RequestMapping("/coupon/coupon/member/list")
public R memberCoupons();
}
然后我们在member的控制层写一个测试请求
@RestController
@RequestMapping("member/member")
public class MemberController {
@Autowired
private MemberService memberService;
@Autowired
CouponFeignService couponFeignService;
@RequestMapping("/coupons")
public R test() {
MemberEntity memberEntity = new MemberEntity();
memberEntity.setNickname("张三");
// 假设张三去数据库查了后返回了张三的优惠券信息
R memberCoupons = couponFeignService.memberCoupons();
// 打印会员和优惠券信息
return R.ok().put("member", memberEntity).put("coupons", memberCoupons.get("coupons"));
}
......
}
重新启动服务
http://localhost:8000/member/member/coupons
{"msg":"success","code":0,"coupons":[{"id":null,"couponType":null,"couponImg":null,"couponName":"满100减10","num":null,"amount":null,"perLimit":null,"minPoint":null,"startTime":null,"endTime":null,"useType":null,"note":null,"publishCount":null,"useCount":null,"receiveCount":null,"enableStartTime":null,"enableEndTime":null,"code":null,"memberLevel":null,"publish":null}],"member":{"id":null,"levelId":null,"username":null,"password":null,"nickname":"张三","mobile":null,"email":null,"header":null,"gender":null,"birth":null,"city":null,"job":null,"sign":null,"sourceType":null,"integration":null,"growth":null,"status":null,"createTime":null}}
引入Nacos作为配置中心
参考:官方介绍
1. common模块引入nacos-config依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2. 配置 Nacos Config 元数据
在服务模块新建bootstrap.properties
此处以coupon服务为例:
spring.application.name=mall-coupon
spring.cloud.nacos.config.server-addr=localhost:8848
3. 测试读取配置中心配置
给配置中心新增一个配置
读取配置
application.properties
coupon.user.name=zhangsan2
coupon.user.age=20
CouponController.java
@RefreseScope:动态刷新,修改配置中心配置不需要重新启动项目
@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
@Value("${coupon.user.name}")
private String name;
@Value("${coupon.user.age}")
private Integer age;
@RequestMapping("/test")
public R test() {
return R.ok().put("name", name).put("age", age);
}
}
请求 /coupon/coupon/test
可以看到配置中心的数据,修改配置中心的配置,刷新可自动更新,nacos的配置内容优先于项目本地的配置内容。
4. Nacos 命名空间
为了对不同服务之间进行配置隔离,这里为每个微服务创建自己的命名空间。
后端代码中在 bootstrap.properties 配置属于自己服务的命名空间
spring.application.name=mall-coupon
spring.cloud.nacos.config.server-addr=localhost:8848
spring.cloud.nacos.config.namespace=eed1d158-6019-487f-b38a-cf79430eba44
5. 加载多配置集
- 配置集:一组相关或不相关配置项的集合。
- 配置集ID:类似于配置文件名,即Data ID
- 配置分组:默认所有的配置集都属于DEFAULT_GROUP。自己可以创建分组,比如双十一,618,双十二
spring.cloud.nacos.config.group=DEFAULT_GROUP # 更改配置分组
最终方案:每个微服务创建自己的命名空间,然后使用配置分组区分环境(dev/test/prod)
把原来application.yml里的内容都分文件抽离出去,在nacos里创建好后,指定coupons要导入的配置即可。
datasource.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.1.103:3306/mall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
mybatis.yml
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto
other.yml ```yaml spring: application: name: mall-coupon cloud: nacos:
discovery:
server-addr: localhost:8848
server: port: 7000
注释application.yml的内容<br />修改coupon里的bootstrap.properties
```yaml
# 改名字,对应nacos里的配置文件名
spring.application.name=mall-coupon
spring.cloud.nacos.config.server-addr=localhost:8848
# 可以选择对应的命名空间 ,即写上对应环境的命名空间ID
spring.cloud.nacos.config.namespace=eed1d158-6019-487f-b38a-cf79430eba44
# 配置文件所在的组
spring.cloud.nacos.config.group=dev
# 加载多配置集
spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
spring.cloud.nacos.config.ext-config[0].group=dev
spring.cloud.nacos.config.ext-config[0].refresh=true
spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
spring.cloud.nacos.config.ext-config[1].group=dev
spring.cloud.nacos.config.ext-config[1].refresh=true
spring.cloud.nacos.config.ext-config[2].data-id=other.yml
spring.cloud.nacos.config.ext-config[2].group=dev
spring.cloud.nacos.config.ext-config[2].refresh=true
引入Gateway作为API网关
参考:官网
创建网关子模块mall-gateway
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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ht.mall</groupId>
<artifactId>mall-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mall-gateway</name>
<description>API网关</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>groupId</groupId>
<artifactId>mall-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
主启动类
@EnableDiscoveryClient
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MallGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(MallGatewayApplication.class, args);
}
}
配置nacos注册中心地址applicaion.properties
spring.application.name=mall-gateway
spring.cloud.nacos.discovery.server-addr=localhost:8848
server.port=88
bootstrap.properties 填写配置中心地址
spring.application.name=mall-gateway
spring.cloud.nacos.config.server-addr=localhost:8848
spring.cloud.nacos.config.namespace=cfc9231c-e4d3-4f2e-ad7a-c12faffbf7dc
在gateway命名空间里创建文件mall-gateway.yml
spring:
application:
name: mall-gateway
在项目里创建application.yml
spring:
cloud:
gateway:
routes:
#Query A 参数有A就行,Query B,C 参数B的值为C即可
#实现针对于“http://localhost:88/hello?url=baidu”,转发到“https://www.baidu.com/hello”,
#针对于“http://localhost:88/hello?url=qq”的请求,转发到“https://www.qq.com/hello”
- id: baidu_route
uri: http://www.baidu.com
predicates:
- Query=url,baidu
- id: test_route
uri: http://www.qq.com
predicates:
- Query=url,qq
测试:
启动项目分别请求:
localhost:88?url=baidu
localhost:88?url=qq
会分别跳转到百度和github 表示成功。