SpringCloud Alibaba
简介和缘由
SpringCloud 的几大痛点
SpringCloud 部分组件停止维护和更新,给开发带来不便;比如eureka停止运维
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,即分布式事务解决方案
版本选择
由于 Spring Boot 1 和 Spring Boot 2 在 Actuator 模块的接口和注解有很大的变更,
且spring-cloud-commons 从 1.x.x 版本升级到 2.0.0 版本也有较大的变更,
因此我们采取跟SpringBoot 版本号一致的版本:
1.5.x 版本适用于 Spring Boot 1.5.x
2.0.x 版本适用于 Spring Boot 2.0.x
2.1.x 版本适用于 Spring Boot 2.1.x
项目中导入依赖
在 common 项目中引入如下。进行统一管理
<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作为注册中心
首先,修改 pom.xml 文件,引入 Nacos Discovery Starter。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
然后在应用的 /src/main/resources/application.properties 配置文件中配置 Nacos Server 地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication
{
public static void main(String[] args)
{
SpringApplication.run(ProviderApplication.class, args);
}
@RestController
class EchoController
{
@GetMapping(value = "/echo/{string}")
public String echo(@PathVariable String string)
{
return string;
}
}
}
最后还需要给应用起一个名字才能注册到服务中心
spring:
datasource:
username: root
password: 123
url: jdbc:mysql://10.235.140.206:3306/gulimall_oms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.jdbc.Driver
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: coupon
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto
feign 远程调用
注册剩下的服务上去,然后使用open-feign进行服务之间的远程调用
Feign 声明式远程调用
简介
Feign 是一个声明式的 HTTP 客户端,它的目的就是让远程调用更加简单。Feign 提供了 HTTP
请求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地
址等信息。
Feign 整合了 Ribbon(负载均衡)和 Hystrix(服务熔断),可以让我们不再需要显式地使用这
两个组件。
SpringCloudFeign 在 NetflixFeign 的基础上扩展了对 SpringMVC 注解的支持,在其实现下,我
们只需创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定。简化了
SpringCloudRibbon 自行封装服务调用客户端的开发量。
使用
1、引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、开启 feign 功能
package com.jane.shop.member;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 远程调用服务的步骤:
* 1.首先得引入openfeign
* 2.编写一个接口,告诉spring cloud这个接口需要调用的远程服务
* 接口里面声明的方法都是调用哪个远程服务的哪个请求
* 3.开启远程调用功能,里面的basePackages说明远程调用的接口在哪里
*/
@EnableFeignClients(basePackages = "com.jane.shop.member.feign")
@SpringBootApplication
@EnableDiscoveryClient
public class MemberApplication
{
public static void main(String[] args)
{
SpringApplication.run(MemberApplication.class, args);
}
}
3、声明远程接口
package com.jane.shop.member.feign;
import com.jane.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author jane
* @create 2021-03-03 15:05
* 首先得@FeignClient("coupon")声明这是个远程客户端,里面写在注册中心注册的服务名
* 然后再接口里面写对应这个服务提供服务的抽象方法,路径要写完整的路径
*/
@FeignClient("coupon")
public interface CouponFeignService
{
@RequestMapping("/coupon/coupon/member/list")
public R membercoupon();
}
SpringCloud Alibaba-Nacos作为配置中心
/**
* 1、如何使用Nacos作为配置中心统一管理配置
*
* 1)、引入依赖,
* <dependency>
* <groupId>com.alibaba.cloud</groupId>
* <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
* </dependency>
* 2)、创建一个bootstrap.properties。
* spring.application.name=coupon
* spring.cloud.nacos.config.server-addr=127.0.0.1:8848
* 3)、需要给配置中心默认添加一个叫 数据集(Data Id)coupon.properties。默认规则,应用名.properties
* 4)、给 应用名.properties 添加任何配置
* 5)、动态获取配置。
* @RefreshScope:动态获取并刷新配置
* @Value("${配置项的名}"):获取到配置。
* 如果配置中心和当前应用的配置文件中都配置了相同的项,优先使用配置中心的配置。
*/
这里我暂时是有bug,解决不了
配置中心的细节
命名空间
用来做配置隔离的,默认使用的是public(保留空间)
默认新增的所有配置都在public空间。
比如我们有开发环境,测试环境,生产环境:利用命名空间来做环境隔离。
注意:在bootstrap.properties;配置上,需要说明使用哪个命名空间下的配置,
spring.cloud.nacos.config.namespace=69c39f7b-107c-4995-b0b3-643ff4a392ff
比如我们每个微服务都有自己的配置,配置文件众多,
每一个微服务之间互相隔离配置,每一个微服务都创建自己的命名空间,
只加载自己命名空间下的所有配置
配置集
所有的配置的集合
配置集ID
配置集ID:类似文件名。
Data ID:类似文件名
配置分组
默认所有的配置集都属于:DEFAULT_GROUP;
比如双十一使用111,
还有其他的节日活动:618,1212
然后需要在配置文件里面配置(DEFAULT_GROUP就是对应的组名)
spring.cloud.nacos.config.group=DEFAULT_GROUP
然后现在我们想的是:
项目中的使用:每个微服务创建自己的命名空间,使用配置分组区分环境,dev,test,prod
同时加载多个配置集
1)、微服务任何配置信息,任何配置文件都可以放在配置中心中
2)、只需要在bootstrap.properties说明加载配置中心中哪些配置文件即可
3)、@Value,@ConfigurationProperties。。。
以前SpringBoot任何方法从配置文件中获取值,都能使用。
配置中心有的优先使用配置中心中的,
比如现在我们按照数据库的配置,mybatis的配置,和其他配置的分类
将配置分类,然后再在bootstrap.properties进行说明
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
spring cloud的gateway网关
动态上下线:
发送请求需要知道商品服务的地址,如果商品服务器有123服务器,1号掉线后,还得改,
所以需要网关动态地管理,他能从注册中心中实时地感知某个服务上线还是下线。
【先通过网关,网关路由到服务提供者】
拦截:请求也要加上询问权限,看用户有没有权限访问这个请求,也需要网关。
所以我们使用spring cloud的gateway组件做网关功能。
网关是请求流量的入口,常用功能包括路由转发,权限校验,限流控制等。
springcloud gateway取代了zuul网关。
三大核心概念
Route:
The basic building block of the gateway.
It is defined by an ID, a destination URI, a collection of predicates,
and a collection of filters.
A route is matched if the aggregate predicate is true.
发一个请求给网关,网关要将请求路由到指定的服务。
路由有id,目的地uri,断言的集合,匹配了断言就能到达指定位置,
Predicate断言:
This is a Java 8 Function Predicate.
The input type is a Spring Framework ServerWebExchange.
This lets you match on anything from the HTTP request,
such as headers or parameters.
就是java里的断言函数,匹配请求里的任何信息,包括请求头等。根据请求头路由哪个服务
Filter:
These are instances of Spring Framework GatewayFilter that have been
constructed with a specific factory.
Here, you can modify requests and responses before or after
sending the downstream request.
过滤器请求和响应都可以被修改。
客户端发请求给服务端。中间有网关。先交给映射器,
如果能处理就交给handler处理,然后交给一系列filer,
然后给指定的服务,再返回回来给客户端。
断言例子
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
比如上面的断言,-代表数组,后面还可以写很多的断言
The After route predicate factory takes one parameter,
a datetime (which is a java ZonedDateTime).
This predicate matches requests that happen after the specified datetime.
The following example configures an after route predicate
所以这个断言就是在这个时间之后的请求都能匹配成功
过滤器例子
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
The AddRequestHeader GatewayFilter factory takes a name and value parameter.
The following example configures an AddRequestHeader GatewayFilter
这个过滤器没有断言,所以所有的请求都会来到这里,然后路由到uri去
但是经过这个过滤器的都会在请求头加上X-Request-red : blue这个键值对参数
创建网关
创建,使用initilizer,
Group:com.jane.shop,
Artifact: gateway,
package:com.jane.shop.gateway。
搜索gateway选中。
pom.xml里加上common依赖, 修改jdk版本,
开启注册服务发现@EnableDiscoveryClient
配置nacos注册中心地址applicaion.properties
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.application.name=gateway
server.port=88
bootstrap.properties 填写nacos配置中心地址
在nacos配置好相应的配置
spring.application.name=gateway
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=48b8175f-ceab-40f4-9042-899f966e6858
spring.cloud.nacos.config.group=dev
在项目里创建application.yml,根据条件转发到uri等
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.
The preceding route matches if the request contained a red query parameter
whose value matched the gree. regexp, so green and greet would match.
根据官网,这是匹配请求中带有参数red,并且参数的值是gree的正则表达式
下面我们写成这样测试去百度行不行
spring:
cloud:
gateway:
routes:
- id: test_route
uri: https://www.baidu.com
predicates:
- Query=url,baidu