在 common 项目的pom.xml中引入如下。进行统一管理
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>2.1.0.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
Nacos 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理
平台。他是使用 java 编写。需要依赖 java 环境
Nacos 文档地址: https://nacos.io/zh-cn/docs/quick-start.html
https://github.com/alibaba/nacos/releases
注意这里遇到了一个坑!
在解压下载到的nacos-server文件时,注意路径中不能有中文!!不然启动过程中有可能会报错
还有一个坑!
注意在本地windows系统中运行不了的话可以尝试一下:
第一种解决方法:在bin中打开可编辑的(可用记事本或写字板)startup.cmd,然后将 MODE="cluster"改为MODE=“standalone”
第二种解决方法:在nacos/bin路径下进入cmd,使用
startup.cmd -m standalone
进行单机启动
参考文章:windows环境下nacos单机启动两种方式
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
要注意application.properties中的是spring.cloud.nacos.discovery.server-addr,不要与bootstrap.properties中的搞混了
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
# 注意:每一个应用都应该有名字,这样才能注册上去。修改 application.properties 文件
# 设置该微服务的名字(service-provider改为具体所需名字)
spring.application.name=service-provider
# 在8000端口启动该服务
server.port=8000
在服务列表中查看到刚刚启动的应用则代表该服务在nacos上注册成功
小总结:
Nacos 使用三步
1、导包 nacos-discovery
2、写配置,指定 nacos 地址,指定应用的名字
3、开启服务注册发现功能@EnableDiscoveryClient
声明式远程调用: feign是一个声明式的HTTP客户端,他的目的就是让远程调用更加简单。 给远程服务发的是HTTP请求。
1 会员服务想要远程调用优惠券服务,只需要在会员服务里引入openfeign依赖,他就有了远程调用其他服务的能力。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
注意!!有个坑!
在较新版本的SpringBoot中要在需要调用别的服务的微服务的pom.xml中添加spring-cloud-loadbalancer依赖 并且在nacos中排除ribbon依赖
具体参考文章:SpringCloud整合Feign和Nacos报错:No Feign Client for loadBalancing defined. Did you forget to include?
在优惠券服务中的controller文件编写代码用于测试
@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));
}
注意在需要调用别的服务的服务中要新建一个feign包如下
在包中新建需要调用的服务的接口文件
文件中加上注解:
//告诉spring cloud这个接口是一个远程客户端,要调用coupon服务,再去调用coupon服务/coupon/coupon/member/list对应的方法
@FeignClient("..-coupon")
括号中填的是该服务(会员服务)需要调用的服务(优惠券服务)的服务名字(nacos注册中心中该服务的名字)
这样我们准备好了优惠券的调用内容,在member(会员服务)的Application中加注解@EnableFeignClients(basePackages=“…feign”),
注意此处填写的是feign包的路径
告诉spring这里面是一个远程调用客户端,member要调用的接口
CouponFeignService中编写需要调用的方法声明出来
@FeignClient("gulimall-coupon")
public interface CouponFeignService {
/**
* 把需要使用的方法声明出来(注解里的路径要写全)
* 注意CouponController外还有一层coupon/coupon,所以完整路径中要加上!
*/
@RequestMapping("coupon/coupon/member/list")
public R membercoupons();
}
注意RequestMapping的地址,在编写的测试代码中
我们可以看到在CouponController外面还有一层coupon/coupon,与需要调用的方法membercoupons()外面的/member/list结合可知,需要写的“完整”路径为coupon/coupon/member/list
然后我们在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"));
}
重新启动优惠券服务与会员服务
在浏览器中输入以下url进行测试(8000为会员服务的端口)
http://localhost:8000/member/member/coupons
若成功返回对应的内容,则证明使用feign远程调用成功
小总结:
Feign 使用三步
1、导入 openfeign依赖
2、开启@EnableFeignClients 功能
3、编写接口,进行远程调用
更多配置:https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/na
cos-example/nacos-discovery-example/readme-zh.md#more
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
新建bootstrap.properties配置文件
在bootstrap.properties中配置应用名和配置中心地址
nacos-config-example对应nacos中配置文件的名字,根据该服务的名字起名
spring.application.name=nacos-config-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
注意了注意了!
这里bootstrap.properties中的是spring.cloud.nacos.config.server-addr
而在application.properties中的是spring.cloud.nacos.discovery.server-addr
注意:在较新版本的SpringBoot中SpringCloud中Bootstrap配置的生效问题
在 nacos 中创建一个 应用名.properties 配置文件并编写配置
Nacos Config 数据结构
Nacos Config 主要通过 dataId 和 group 来唯一确定一条配置。
Nacos Client 从 Nacos Server 端获取数据时,调用的是此接口 ConfigService.getConfig(String
dataId, String group, long timeoutMs)。
在配置列表中点+号即可创建配置文件
在这里可以将该服务原来的application.properties文件迁移到此处
Group:
Group 默认为 DEFAULT_GROUP,可以通过 spring.cloud.nacos.config.group 配置。
完成上述两步后,应用会从 Nacos Config 中获取相应的配置,并添加在 Spring Environment的 PropertySources 中 。 这 里 我 们 使 用 @Value 注 解 来 将 对 应 的 配 置 注 入 到SampleController 的 userName 和 age 字段,并添加 @RefreshScope 打开动态刷新功能
@RefreshScope
class SampleController {
@Value("${coupon.user.name}")
String userName;
@Value("${coupon.user.age}")
int age;
}
@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
@Value("${coupon.user.name}")//从application.properties中获取//不要写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);
}
}
在nacos浏览器中还可以配置命名空间:用作配置隔离。(一般每个微服务一个命名空间)
默认的命名空间为public。默认新增的配置都在public空间下
开发环境(dev)、测试环境(test)、生产环境(prop)可以用命名空间分割。properties每个空间有一份。
在bootstrap.properties里配置
spring.cloud.nacos.config.namespace=命名空间的id # 可以选择对应的命名空间 ,即写上对应环境的命名空间ID
也可以为每个微服务配置一个命名空间,微服务互相隔离
用不同的命名空间隔离微服务,用不同的Group来隔离开发,测试和生产环境
一组相关或不相关配置项的集合。
类似于配置文件名,即Data Id
默认所有的配置集都属于DEFAULT_GROUP。自己可以创建分组,比如双十一,618,双十二,又比如可以将配置集按生产(prop),测试(test)和开发(dev)等不同环境进行配置的分组
在服务的bootstrap.properties中可以使用
spring.cloud.nacos.config.group=分组的名字 # 更改配置分组
来更改该服务使用的配置组
最终方案:每个微服务创建自己的命名空间(namespace),然后使用==配置分组(group)==区分环境(dev/test/prod)
我们要把原来application.yml里的内容都根据模块功能分成多个yml文件抽离出去。我们在nacos里创建好后,在coupons里指定要导入的配置即可。
例如:
原application.yml
spring:
datasource:
username:
password:
url: jdbc:mysql://ip:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
driver-class-name: com.mysql.cj.jdbc.Driver
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: gulimall-coupon
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto
server:
port: 7000
将该yml文件分成以下几份文件:
mybatis.yml:
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto
datasource.yml:
spring:
datasource:
username:
password:
url: jdbc:mysql://ip:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
driver-class-name: com.mysql.cj.jdbc.Driver
other.yml:
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: gulimall-coupon
server:
port: 7000
然后分别在nacos对应的命名空间的配置列表中创建:
然后在bootstrap.properties中进行以下配置
#主要配置应用名和配置中心地址
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
#设置命名空间(注意写的是对应命名空间的id)
spring.cloud.nacos.config.namespace=260184a3-f862-4218-99d6-8b3f799c7355
spring.cloud.nacos.config.group=dev
#data-id
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
即可完成配置文件的拆分与多配置集的加载
网关作为流量的入口,常用功能包括路由转发、权限校验、限流控制等。而 springcloud gateway作为 SpringCloud 官方推出的第二代网关框架,取代了 Zuul 网关。
客户端发送请求给网关,网关 HandlerMapping 判断是否请求满足某个路由,满足就发给网关的 WebHandler。这个 WebHandler 将请求交给一个过滤器链,请求到达目标服务之前,会执行所有过滤器的 pre 方法。请求到达目标服务处理之后再依次执行所有过滤器的 post 方法。
一句话: 满足某些断言(predicates) 就路由到指定的地址(uri),使用指定的过滤器(filter)
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
// 排除数据库相关的自动配置(用不上数据库)
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
// 开启注册服务发现
@EnableDiscoveryClient
2、在applicaion.properties中配置nacos注册中心地址
spring.application.name=...
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
server.port=88
3、bootstrap.properties 中填写配置中心地址
spring.application.name=微服务名
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=命名空间id
4、nacos里创建命名空间gateway,然后在命名空间里创建文件…-gateway.yml
spring:
application:
name: ...-gateway
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
predicates:
- Query=baz
filters:
- AddRequestParameter=foo, bar
例子:
spring:
cloud:
gateway:
routes:
- 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 # 跳到qq页面
注意:
- 各种 Predicates 同时存在于同一个路由时,请求必须同时满足所有的条件才被这个路由匹配。
- 一个请求满足多个路由的谓词条件时,请求只会被首个成功匹配的路由转发