谷粒商城微服务应用说明
SpringCloud Alibaba
SpringCloud Alibaba 简介
SpringCloud Alibaba 简介
-
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
-
依托Spring Cloud Alibaba,我们只需要添加一些注解和少量配置,就可以将Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
-
github地址:https://github.com/alibaba/spring-cloud-alibaba
为什么使用SpringCloud Alibaba
SpringCloud 的几大痛点:
- SpringCloud 部分组件停止维护和更新,给开发带来不便;
- SpringCloud 部分环境搭建复杂,没有完善的可视化界面,我们需要大量的二次开发和定制
- SpringCloud 配置复杂,难以上手,部分配置差别难以区分和合理应用
SpringCloud Alibaba 的优势:
- 阿里使用过的组件经历了考验,性能强悍,设计合理,现在开源出来大家用
- 成套的产品搭配完善的可视化界面给开发运维带来极大的便利
- 搭建简单,学习曲线低。
结合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,即分布式事务解决方案
SpringCloud Alibaba 整合
详细可以参考官方文档:https://spring.io/projects/spring-cloud-alibaba
- 在 gulimall-common 中引入SpringCloud Alibaba的依赖版本号管理,这样在引入其中某个组件的时候就不用标明版本号了
<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>
SpringCloud Alibaba - Nacos【作为注册中心】
Nacos 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。他是使用Java编写,需要依赖java 环境。
Nacos 文档地址: https://nacos.io/zh-cn/docs/quick-start.html
Nacos 配置:https://github.com/alibaba/spring-cloud-alibaba
nacos-server 下载并启动
Nacos Server 支持直接下载和源码构建两种方式,可以参考官网。
这里我使用Docker部署Naccos,参考:https://blog.csdn.net/qq_36389060/article/details/132418204
Nacos【注册中心】微服务集成
- 在gulimall-common中引入 Nacos【注册中心】依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
- 增加配置,在微服务应用的 /src/main/resources/application.yml 配置文件中配置 Nacos Server 地址,并设置微服务的名称
spring: cloud: nacos: discovery: server-addr: 192.168.217.138:8848 application: name: gulimall-coupon
- 使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
@EnableDiscoveryClient @MapperScan("com.atguigu.gulimall.coupon.dao") @SpringBootApplication public class GulimallCouponApplication { public static void main(String[] args) { SpringApplication.run(GulimallCouponApplication.class, args); } }
- 启动服务,注册成功
SpringCloud Alibaba - Nacos【作为配置中心】
详细可以参考官方文档:https://github.com/alibaba/spring-cloud-alibaba
在没有配置中心之前,传统应用配置的存在以下痛点:
-
采用本地静态配置,无法保证实时性:修改配置不灵活且需要经过较长的测试发布周期,无法尽快通知到客户端,还有些配置对实时性要求很高,比方说主备切换配置或者碰上故障需要修改配置,这时通过传统的静态配置或者重新发布的方式去配置,那么响应速度是非常慢的,业务风险非常大。
-
易引发生产事故:比如在发布的时候,容易将测试环境的配置带到生产上,引发生产事故。
-
配置散乱且格式不标准:有的用properties格式,有的用xml格式,还有的存DB,团队倾向自造轮子,做法五花八门。
-
配置缺乏安全审计、版本控制、配置权限控制功能:谁?在什么时间?修改了什么配置?无从追溯,出了问题也无法及时回滚到上一个版本;无法对配置的变更发布进行认证授权,所有人都能修改和发布配置。
而配置中心区别于传统的配置信息分散到系统各个角落的方式,对系统中的配置文件进行集中统一管理,而不需要逐一对单个的服务器进行管理。那这样做有什么好处呢?
-
通过配置中心,可以使得配置标准化、格式统一化。
-
当配置信息发生变动时,修改实时生效,无需要重新重启服务器,就能够自动感知相应的变化,并将新的变化统一发送到相应程序上,快速响应变化。比方说某个功能只是针对某个地区用户,还有某个功能只在大促的时段开放,使用配置中心后只需要相关人员在配置中心动态去调整参数,就基本上可以实时或准实时去调整相关对应的业务。
-
通过审计功能还可以追溯问题。
这里我遇到了无法从Nacos获取动态配置的问题,如果大家遇到可以参考这篇文章。
Nacos【配置中心】微服务集成
在gulimall-common中引入 Nacos【配置中心】依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
补充说明:Springboot配置文件加载顺序
其实yml和properties文件是一样的原理,且一个项目上要么yml或者properties,二选一的存在。推荐使用yml,更简洁。
(1)加载顺序:这里主要是说明application和bootstrap的加载顺序。
-
bootstrap.yml(bootstrap.properties)先加载
-
application.yml(application.properties)后加载
-
bootstrap.yml 用于应用程序上下文的引导阶段。
-
bootstrap.yml 由父Spring ApplicationContext加载。
(2)配置区别
-
bootstrap.yml 和application.yml 都可以用来配置参数。
-
bootstrap.yml 可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。application.yml 可以用来定义应用级别的。
在应用的 /src/main/resources/bootstrap.properties 配置文件中配置 Nacos Config 地址并引入服务配置
提示:bootstrap.properties 会优先于 application.properties 或 application.yml 进行加载。
spring:
cloud:
nacos:
serverAddr: 192.168.217.138:8848
config:
import:
- nacos:nacos-config-example.properties?refresh=true
Nacos 添加配置
以gulimall-coupon服务为例,当我们配置好Nacos配置中心后,启动服务后,控制台会打印如下内容,表明可以从Nacos中名为
gulimall-coupon.properties
的配置文件中读取配置信息。
Located property source: CompositePropertySource {name='NACOS', propertySources=[NacosPropertySource {name='gulimall-coupon.properties'}]}
创建配置文件:需要给Nacos配置中心默认添加一个 数据集(Data Id),这里为gulimall-coupon.properties。默认规则为 应用名.properties。
- 发布的配置可以在配置列表中看到
如果想动态获取配置还需要在Controller上加 @RefreshScope 注解动态获取并刷新配置
注意: 如果配置中心和当前应用的配置文件中都配置了相同的项,优先使用配置中心的配置。
@RestController
@RequestMapping("coupon/coupon")
@RefreshScope
public class CouponController {
}
代码测试能否动态获取配置信息
- 测试代码
@RestController @RequestMapping("coupon/coupon") @RefreshScope 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); } }
- 本地应用配置文件内容
- Nacos配置中心文件内容
- 测试结果
Nacos 命名空间 - 配置隔离
命名空间的核心作用是用来进行配置隔离。
不同的命名空间下,可以存在相同的 Group 或Data ID 的配置。默认为 public(保留空间),默认新增的所有配置都在public空间。
Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
-
创建开发,测试,生产环境命名空间,利用命名空间来做环境隔离。
-
为gulimall-coupon创建开发环境下的配置
-
在bootstrap.properties上指定使用哪个命名空间下的配置
spring.cloud.nacos.config.namespace=e523efec-62db-4526-be4d-451f8055677e
命名空间除了上面基于环境进行配置隔离的创建方式,也可以每一个微服务都创建自己的命名空间,只加载自己命名空间下的所有配置,实现每一个微服务之间互相隔离配置。
Naocs 配置集【所有的配置的集合】
一组相关或者不相关的配置项的集合称为配置集。在系统中,一个配置文件通常就是一个配置集,包含了系统各个方面的配置。例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。
Naocs 配置集ID(Data ID)
- Data ID:类似文件名
Nacos 克隆配置
可以发现有四个名称空间:public(默认)以及我们自己添加的3个名称空间(prod、dev、test),可以点击查看每个名称空间下的配置文件,当然现在只有public下有一个配置。
默认情况下,项目会到public下找 服务名.properties文件。
接下来,在dev名称空间中也添加一个nacos-provider.properties配置。这时有两种方式:
-
方式一:切换到dev名称空间,添加一个新的配置文件。缺点是每个环境都要重复配置类似的项目
-
方式二:直接通过clone方式添加配置,并修改即可。推荐使用
Nacos 配置分组(Group)
-
默认所有的配置集都属于:DEFAULT_GROUP
-
每个微服务创建自己的命名空间,然后使用配置分组区分环境(dev、test、prod)
-
使用配置分组的时候需要在bootstrap.properties中指定使用的配置分组
spring.cloud.nacos.config.group=dev
Nacos 同时加载多个配置集
在一些情况下需要加载多个配置文件。假如gulimall-coupon现在dev名称空间下有三个配置文件:
-
数据源配置文件 datasource.yml
-
MyBatis配置文件 mybatis.yml
-
其它配置信息文件 other.yml
-
在bootstrap.properties中指定多个配置集
spring.cloud.nacos.config.server-addr=192.168.217.138:8848 # 指定命名空间 spring.cloud.nacos.config.namespace=603d4bc4-6e92-4487-990a-4de97625433e # 指定多个配置集 spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml spring.cloud.nacos.config.extension-configs[0].group=dev # 开启动态刷新配置,否则配置文件修改,工程无法感知 spring.cloud.nacos.config.extension-configs[0].refresh=true spring.cloud.nacos.config.extension-configs[1].data-id=mybatis.yml spring.cloud.nacos.config.extension-configs[1].group=dev spring.cloud.nacos.config.extension-configs[1].refresh=true spring.cloud.nacos.config.extension-configs[2].data-id=other.yml spring.cloud.nacos.config.extension-configs[2].group=dev spring.cloud.nacos.config.extension-configs[2].refresh=true
-
将原有application.yml中的配置信息全部注释进行测试,从控制台打印信息中可以看到服务加载的Nacos配置文件
[subscribe] mybatis.yml+dev+603d4bc4-6e92-4487-990a-4de97625433e [subscribe] other.yml+dev+603d4bc4-6e92-4487-990a-4de97625433e [subscribe] datasource.yml+dev+603d4bc4-6e92-4487-990a-4de97625433e
SpringCloud
Feign - 声明式远程调用
Feign 简介
Feign 是一个声明式的HTTP 客户端,它的目的就是让远程调用更加简单。Feign 提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP 请求的参数、格式、地址等信息。
Feign 整合了Ribbon(负载均衡)和Hystrix(服务熔断),可以让我们不再需要显式地使用这两个组件。
SpringCloudFeign 在NetflixFeign 的基础上扩展了对SpringMVC 注解的支持,在其实现下,我们只需创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定。简化了 SpringCloudRibbon 自行封装服务调用客户端的开发量。
Feign微服务集成
这里以gulimall-member服务调用gulimall-coupon服务为例进行讲解
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
编写gulimall-coupon ==》CouponController测试方法
@RequestMapping("/member/list")
public R memberCoupons() {
CouponEntity couponEntity = new CouponEntity();
couponEntity.setCouponName("满100减10");
return R.ok().put("coupons",Arrays.asList(couponEntity));
}
编写声明式的远程调用接口,,告诉SpringCloud这个接口需要调用远程服务
声明接口的每一个方法都是调用哪个远程服务的那个请求
@FeignClient("gulimall-coupon") // 名称为nacos中的注册名称
public interface CouponFeignService {
/**
* 返回所有会员优惠券
* @return
*/
@RequestMapping("/coupon/coupon/member/list")
public R memberCoupons();
}
使用 @EnableFeignClients 开启远程调用功能
@EnableFeignClients(basePackages = {"com.atguigu.gulimall.member.feign"})
@EnableDiscoveryClient
@MapperScan("com.atguigu.gulimall.member.dao")
@SpringBootApplication
public class GulimallMemberApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallMemberApplication.class, args);
}
}
在gulimall-member ==》MemberController测试方法
@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"));
}
}
开启nacos,访问 http://localhost:8000/member/member/coupons 进行测试
Feign原理 TODO
Gateway 网关
Gateway 介绍
网关作为流量的入口,常用功能包括路由转发、权限校验、限流控制等。而 springcloud gateway 作为 SpringCloud 官方推出的第二代网关框架,取代了Zuul 网关。
网关提供API 全托管服务,丰富的API 管理功能,辅助企业管理大规模的API,以降低管理成本和安全风险,包括协议适配、协议转发、安全策略、防刷、流量、监控日志等功能。
Spring Cloud Gateway 旨在提供一种简单而有效的方式来对API 进行路由,并为他们提供切面,例如:安全性,监控/指标和弹性等。
官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.3.RELEASE/single/spring-clo
ud-gateway.html
三大核心概念
- 路由(Route):当我们发一个请求给网关,网关要将请求路由到指定的服务。路由(Route)由ID、destination URI(目标URI)、a collection of predicates(一组断言集合)、a collection of filters(一组过滤器)组成。如果路由能匹配了断言,那么就能到达指定位置。
- 断言(Predicate):就是java里的断言函数,匹配请求里的任何信息,包括请求头等。根据请求头路由哪个服务
- 过滤(Filter):通过配置 Spring Framework GatewayFilter 可以修改请求和响应。
客户端向 Spring Cloud GateWay网关发出请求,首先交给映射器,如果能处理就交给handler处理,然后交给一系列Filter,然后给指定的服务,再返回回来给客户端。
Gateway 微服务集成
创建网关模块
引入common依赖,将自己注册到nacos中心,发现其他服务
<dependency>
<groupId>com.atguigu.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
在启动类中加上
@EnableDiscoveryClient
注解,开启发现其他服务的功能,因为网关服务不需要数据库的配置,所以在启动类上排除和数据库相关的配置@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDiscoveryClient
//去除数据源配置,否则会报错
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class GulimallGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallGatewayApplication.class, args);
}
}
在nacos中创建网关服务的命名空间,并在配置列表的网关服务的命名空间下创建当前网关的配置
添加注册中心的配置文件bootstrap.properties,指定当前服务,添加注册中心的地址,网关服务的命名空间,网关服务使用的配置分组
spring.application.name=gulimall-gateway
spring.cloud.nacos.config.server-addr=192.168.217.138:8848
# 指定命名空间
spring.cloud.nacos.config.namespace=27d22758-30e4-4cef-aec2-66ff8153d163
Gateway 断言配置
断言配置可以参考官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.3.RELEASE/single/spring-cloud-gateway.html#gateway-request-predicates-factories
-
参考:https://blog.csdn.net/hancoder/article/details/109063671
-
在application.yml中进行断言配置
spring: cloud: gateway: routes: - id: test_route uri: https://www.baidu.com predicates: - Query=url,baidu # url=baidu 则路由到 www.baidu.com - id: qq_route uri: https://www.qq.com predicates: - Query=url,qq
-
测试