SpringCloud Alibaba
一、项目依赖
0、组件
https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
1、项目技术选择
结合 SpringCloud Alibaba 这里使用的技术搭配方案:
SpringCloud Alibaba - Nacos :注册中心(服务发现/ 注册)
SpringCloud Alibaba - Nacos :配置中心(动态配置管理)
SpringCloud - Ribbon :负载均衡
SpringCloud - Feign :声明式 HTTP 客户端(调用远程服务)
SpringCloud Alibaba - Sentinel :服务容错(限流、降级、熔断)
SpringCloud - Gateway :API 网关(webflux 编程模式)
SpringCloud - Sleuth :调用链监控
SpringCloud Alibaba - Seata :原 Fescar ,即分布式事务解决方案
2、版本选择
所以阿昌这里选择如下版本:
-
SpringBoot:
-
SpringCloud Alibaba:
在achangmall-common 的pom.xml中加入:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在别的服务模块的pom.xml中将springboot的版本修改为
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/>
</parent>
二、SpringCloud Alibaba-Nacos
Nacos 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。他是使用 java 编写。需要依赖 java 环境
Nacos 文档地址: https://nacos.io/zh-cn/docs/quick-start.html
1、下载 nacos-server
https://github.com/alibaba/nacos/releases
以下win版本为例
2、启动 nacos-server
- 双击 bin 中的 startup.cmd 文件
- 访问 http://localhost:8848/nacos/
- 使用默认的 nacos/nacos 进行登录
如果出现nacos is starting with cluster
可以尝试使用cmd命令行去指定使用单体模式启动,如下:
startup.cmd -m standalone
3、将微服务注册到 nacos 中
- 首先,修改achangmall-common中的pom.xml 文件,引入 Nacos Discovery Starter 依赖。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 在应用的common中的application.yml 配置文件中配置
Nacos Server 地址 和微服务名称
如下举个例子,把现在所有的服务都加入如下配置,让他注册到nacos中
spring:
datasource:
password: root
username: root
url: jdbc:mysql://192.168.109.101:3306/achangmall_sms?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.jdbc.Driver
application:
name: achangmall-coupon
cloud:
nacos:
discovery:
server-addr: localhost:8848
在每个服务的主入口上标注注解@EnableDiscoveryClient (现在默认不需要标注)
@SpringBootApplication
@MapperScan("com.achang.achangmall.coupon.dao")
@EnableDiscoveryClient
public class AchangmallCouponApplication {
public static void main(String[] args) {
SpringApplication.run(AchangmallCouponApplication.class, args);
}
}
再刷新nacos,查看,发现服务已经注册进nacos了!!!
4、测试member和coupon的远程调用
想要获取当前会员领取到的所有优惠券。先去注册中心找优惠券服务, 注册中心调一台优惠券服务器给会员,会员服务器发送请求给这台优 惠券服务器,然后对方响应。
在调用方的主函数头上标注注解打开远程调用,并指定包位置
@EnableFeignClients(basePackages = "com.achang.achangmall.member.feign")
@SpringBootApplication
@MapperScan("com.achang.achangmall.member.dao")
public class AchangmallMemberApplication {
public static void main(String[] args) {
SpringApplication.run(AchangmallMemberApplication.class, args);
}
}
coupon服务 中被调用接口
@RequestMapping("/member/list")
public R memberCoupon(){
CouponEntity couponEntity = new CouponEntity();
couponEntity.setCouponName("满一百减10");
return R.ok().put("list",Arrays.asList(couponEntity));
}
member服务 中创建feign包,并在下面创建CouponFeignService;
@FeignClient("achangmall-coupon")
public interface CouponFeignService {
final String headUrl = "/coupon/coupon";
@GetMapping(headUrl+"/member/list")
public R memberCoupon();
}
然后阿昌这里启动member服务 ,报了No Feign Client for loadBalancing defined.Did you forget to include spring-cloud-starter-loadbalance 错误
解决方案:
在achangmall-common中修改并引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
在member服务中添加测试接口,测试远程调用
@RestController
@RequestMapping("member/member")
public class MemberController {
@Autowired
private CouponFeignService couponFeignService;
@GetMapping("/test")
public R test(){
MemberEntity memberEntity = new MemberEntity();
memberEntity.setNickname("阿昌");
R r = couponFeignService.memberCoupon();
return R.ok().put("member",memberEntity).put("coupon",r.get("list"));
}
}
重启member服务,并访问:http://localhost:8000/member/member/test ,调用成功!
5、配置中心
我们还可以用nacos作为配置中心。配置中心的意思是不在application.properties 等文件中配置了,而是放到nacos配置中心公用 ,这样无需每台机器都改。
https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md -----官方文档
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
- 在coupons项目中创建/src/main/resources/bootstrap.properties ,这个文件是 springboot里规定的,他优先级别application.properties高
# application.properties
coupon.name=achang
coupon.age=18
# bootstrap.properties
#springboot里规定的,bootstrap.properties的优先级比application.properties高
# 改名字,对应nacos里的配置文件名
spring.application.name=achangmall-coupon
spring.cloud.nacos.config.server-addr=localhost:8848
@Value("${coupon.name}")
private String name;
@Value("${coupon.age}")
private Integer age;
@GetMapping("/test")
public R test(){
return R.ok().put("name",name).put("age",age);
}
- 在Controller加上
@RefreshScope 来动态获取配置数据
这里阿昌遇到了问题:
发现我项目里配置的bootstarp.properties不生效,所以就无法知道远程配置中心的内容;
这里缺少了依赖,因为我使用的是2020以上的版本
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.0.3</version>
</dependency>
具体的maven仓库:
https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-bootstrap
- 测试再访问http://localhost:7000/coupon/coupon/test,动态刷新配置成功
6、配置中心进阶
用作配置隔离。(一般每个微服务一个命名空间)
在nacos中创建对应的名称空间
在创建对应配置文件中指定对于的名称空间
通过spring.cloud.nacos.config.namespace 在指定使用哪个名称空间
spring.cloud.nacos.config.namespace=ed042b3b-b7f3-4734-bdcb-0c516cb357d7 # 可以选择对应的命名空间 ,即写上对应环境的命名空间ID
类似于配置文件名,即Data ID
默认所有的配置集都属于DEFAULT_GROUP。自己可以创建分组,比如双十一,618,双十二
最终方案:每个微服务创建自己的命名空间,然后使用配置分组区分环境(dev/test/prod)
spring.cloud.nacos.config.group=DEFAULT_GROUP # 更改配置分组
将一个配置文件,抽取成多个配置文件
bootstrap.properties
#服务名
spring.application.name=achangmall-coupon
#配置中心地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
#可以选择对应的命名空间 ,即写上对应环境的命名空间ID
spring.cloud.nacos.config.namespace=ed042b3b-b7f3-4734-bdcb-0c516cb357d7
# 配置文件所在的组
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
#mybaits配置
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
7、GateWay网关
网关是请求浏览的入口 ,常用功能包括路由转发,权限校验,限流控制等。springcloud gateway取到了zuul网关。
-
发送请求需要知道商品服务的地址,如果商品服务器有100服务器,1号掉线后, 还得改所以需要网关动态地管理,他能从注册中心中实时地感知某个服务上 线还是下线。 -
请求也要加上询问权限,看用户有没有权限访问这个请求,也需要网关。 -
三大核心概念:
- Route:
- 发一个请求给网关,网关要将请求路由到指定的服务。路由有id,目的地uri,断言的集合,匹配了断言就能到达指定位置,
- Predicate
- java里的断言函数,匹配请求里的任何信息,包括请求头等
- Filter
-
客户端发请求给服务端。中间有网关。先交给映射器,如果能处理就交给handler 处理,然后交给一系列filer,然后给指定的服务,再返回回来给客户端。 -
流程图 -
创建模块achangmall-gateway
<dependency>
<groupId>com.achang.achangmall</groupId>
<artifactId>achangmall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
- 开启注册服务发现@EnableDiscoveryClient
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDiscoveryClient
public class AchangmallGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(AchangmallGatewayApplication.class, args);
}
}
- 配置nacos注册中心地址applicaion.properties
spring.application.name=achangmall-gateway
spring.cloud.nacos.discovery.server-addr=localhost:8848
server.port=88
- bootstrap.properties 填写配置中心地址
spring.application.name=achangmall-gateway
spring.cloud.nacos.config.server-addr=localhost:8848
spring.cloud.nacos.config.namespace=d4b1e29c-de65-47fb-9817-334099a69352
- nacos里创建命名空间gateway,然后在命名空间里创建文件achangmall-gateway.yml
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
http://localhost:88/?url=qq
http://localhost:88/?url=baidu
|