1 springcloud注册中心——Euraka
1.1 EurakaServer
1.1.1 依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
1.1.2 properties.yml配置
server:
port: 9000 #端口
eureka:
instance:
hostname: localhost #主机地址
client:
register-with-eureka: false #是否将自己注册到注册中心(搭建集群改为true)
fetch-registry: false #是否从eureka中获取注册信息(搭建集群改为true)
service-url: #配置暴露给Eureka Client的请求地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
server: #客户端30s发送心跳,服务端90s验证是否有该服务,15分钟心跳低于85%开启保护模式
enable-self-preservation: false #关闭自我保护
eviction-interval-timer-in-ms: 4000 #剔除服务间隔
1.1.3 注解
@EnableEurekaServer
2.1 EurakaClient
1.2.1 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
1.2.2 properties.yml配置
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/ #搭建集群时用逗号隔开注册中心地址
instance:
prefer-ip-address: true #使用ip地址注册
instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心中注册服务id
lease-expiration-duration-in-seconds: 10 #eureka client发送心跳给server端后,续约到期时间(默认90秒)
lease-renewal-interval-in-seconds: 5 #发送心跳续约间隔(默认三十秒)
1.2.3 注解
@EnableEurekaClient
@EnableDiscoveryClient
1.2.4 使用案列
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
/**
* 注入DiscoveryClient :
* springcloud提供的获取原数组的工具类
* 调用方法获取服务的元数据信息
*
*/
//调用discoveryClient方法
//已调用服务名称获取所有的元数据
List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
//获取唯一的一个元数据
ServiceInstance instance = instances.get(0);
//根据元数据中的主机地址和端口号拼接请求微服务的URL
Product product = null;
//如何调用商品服务?
product = restTemplate.getForObject("http://"+instance.getHost()+":"+instance.getPort()+"/product/1",Product.class);
return product;
2 springcloud注册中心——Consul
2.1 EurakaClient
2.1.1 依赖
<!--springcloud 提供的对基于consul的服务发现-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--actuator的健康检查-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.1.2 properties.yml配置
###开始配置consul的服务注册
cloud:
consul:
host: 127.0.0.1 #consul服务器的主机地址
port: 8500 #consul服务器的ip地址
discovery:
#是否需要注册
register: true
#注册的实例ID (唯一标志)
instance-id: ${spring.application.name}-1
#服务的名称
service-name: ${spring.application.name}
#服务的请求端口
port: ${server.port}
#指定开启ip地址注册
prefer-ip-address: true
#当前服务的请求ip
ip-address: ${spring.cloud.client.ip-address}
2.1.3 注解
无
2.1.4 使用案列
由于 SpringCloud 对 Consul 进行了封装。对于在消费者端获取服务提供者信息和 Eureka 是一致的。同样使用 DiscoveryClient 完成调用获取微服务实例信息。
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
/**
* 注入DiscoveryClient :
* springcloud提供的获取原数组的工具类
* 调用方法获取服务的元数据信息
*
*/
//调用discoveryClient方法
//已调用服务名称获取所有的元数据
List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
//获取唯一的一个元数据
ServiceInstance instance = instances.get(0);
//根据元数据中的主机地址和端口号拼接请求微服务的URL
Product product = null;
//如何调用商品服务?
product = restTemplate.getForObject("http://"+instance.getHost()+":"+instance.getPort()+"/product/1",Product.class);
return product;
3 springcloud注册中心——Ribbon
3.1 EurakaServer
3.1.1 依赖
在 springcloud 提供的服务发现的 jar 中以及包含了 Ribbon 的依赖。所以这里不需要导入任何额外的坐标。
<!-- 引入重试的坐标-->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
3.1.2 properties.yml配置
#修改ribbon的负载均衡策略 服务名 - ribbon - NFLoadBalancerRuleClassName : 策略
service-product:
ribbon:
ConnectTimeout: 250 # Ribbon的连接超时时间
ReadTimeout: 1000 # Ribbon的数据读取超时时间
OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
MaxAutoRetries: 1 # 对当前实例的重试次数
3.1.3 注解
@LoadBalanced : 是ribbon提供的负载均衡的注解,加在restTemplate类上
@LoadBalanced
3.1.4 使用案列
/**
* 基于ribbon的形式调用远程微服务
* 1.使用@LoadBalanced声明RestTemplate
* 2.使用服务名称替换ip地址
*/
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
Product product = null;
product = restTemplate.getForObject("http://service-product/product/1",Product.class);
return product;
}
4 springcloud注册中心——Feign
4.1 Feign
4.1.1 依赖
<!--springcloud整合的openFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
4.1.2 properties.yml配置
#配置feign日志的输出
#日志配置 NONE : 不输出日志(高) BASIC: 适用于生产环境追踪问题
#HEADERS : 在BASIC的基础上,记录请求和响应头信息 FULL : 记录所有
feign:
client:
config:
service-product: #需要调用的服务名称
#配置Feign的日志级别,相当于代码配置的Logger
loggerLevel: FULL
#Feign错误码解析器,相当于代码配置方式的ErrorDecoder
errorDecoder: com.example.SimpleErrorDecoder
#配置重试,相当于代码配置方式中的retryer
retryer: com.example.Example.SimpleRetryer
#配置拦截器,相当于代码配置方式中的RequestInterceptor
requestInterceptors:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
decode404: false
compression:
request:
enabled: true # 开启请求压缩
mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
min-request-size: 2048 # 设置触发压缩的大小下限
response:
enabled: true # 开启响应压缩
logging:
level:
cn.itcast.order.feign.ProductFeignClient: debug#配置feign日志的输出
#日志配置 NONE : 不输出日志(高) BASIC: 适用于生产环境追踪问题
#HEADERS : 在BASIC的基础上,记录请求和响应头信息 FULL : 记录所有
feign:
client:
config:
service-product: #需要调用的服务名称
#配置Feign的日志级别,相当于代码配置的Logger
loggerLevel: FULL
#Feign错误码解析器,相当于代码配置方式的ErrorDecoder
errorDecoder: com.example.SimpleErrorDecoder
#配置重试,相当于代码配置方式中的retryer
retryer: com.example.Example.SimpleRetryer
#配置拦截器,相当于代码配置方式中的RequestInterceptor
requestInterceptors:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
decode404: false
compression:
request:
enabled: true # 开启请求压缩
mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
min-request-size: 2048 # 设置触发压缩的大小下限
response:
enabled: true # 开启响应压缩
logging:
level:
cn.itcast.order.feign.ProductFeignClient: debug
4.1.3 注解
@EnableFeignClients
4.1.4 使用案列
1、创建调用方法Feign接口
/**
* 声明需要调用的微服务名称
* @FeignClient
* * name : 服务提供者的名称
*/
@FeignClient(name="service-product")
public interface ProductFeignClient {
/**
* 配置需要调用的微服务接口
*/
@RequestMapping(value="/product/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable("id") Long id);
}
2、调用服务
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private ProductFeignClient productFeignClient;
/**
*/
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
Product product = null;
product = productFeignClient.findById(id);
return product;
}
}
5 springcloud注册中心——Hystrix
5.1 RestTemplate-Hystrix
5.1.1 依赖
<!--引入hystrix依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
5.1.2 properties.yml配置
hystrix:
command:
default:
execution:
isolation:
strategy: ExecutionIsolationStrategy.SEMAPHORE #信号量隔离
#strategy: # ExecutionIsolationStrategy.THREAD 线程池隔离
thread:
timeoutInMilliseconds: 3000 #默认的连接超时时间1秒,若1秒没有返回数据,自动的触发降级逻辑
circuitBreaker:
requestVolumeThreshold: 5 #触发熔断的最小请求次数,默认20 /10秒
sleepWindowInMilliseconds: 10000 #熔断多少秒后去尝试请求 默认 5 打开状态的时间
errorThresholdPercentage: 50 #触发熔断的失败请求最小占比,默认50%
#开启所以健康检查的服务
management:
endpoints:
web:
exposure:
include: '*'
5.1.3 注解
//激活hystrix
@EnableCircuitBreaker
5.1.4 使用案列
@RestController
@RequestMapping("/order")
/**
* @DefaultProperties : 指定此接口中公共的熔断设置
* 如果过在@DefaultProperties指定了公共的降级方法
* 在@HystrixCommand不需要单独指定了
*/
//@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
/**
* 使用注解配置熔断保护
* fallbackmethod : 配置熔断之后的降级方法
*/
@HystrixCommand(fallbackMethod = "orderFallBack")
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
if(id != 1) {
throw new RuntimeException("服务器异常");
}
return restTemplate.getForObject("http://service-product/product/1",Product.class);
}
/**
* 降级方法
* 和需要收到保护的方法的返回值一致
* 方法参数一致
*/
public Product orderFallBack(Long id) {
Product product = new Product();
product.setProductName("触发降级方法");
return product;
}
}
5.2 Feign-Hystrix
5.2.1 依赖
<!--引入hystrix依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
5.2.2 properties.yml配置
#配置feign日志的输出
#日志配置 NONE : 不输出日志(高) BASIC: 适用于生产环境追踪问题
#HEADERS : 在BASIC的基础上,记录请求和响应头信息 FULL : 记录所有
feign:
client:
config:
service-product: #需要调用的服务名称
loggerLevel: FULL
#开启对hystrix的支持
hystrix:
enabled: true
#hystrix对外暴露的所有端点
management:
endpoints:
web:
exposure:
include: '*'
#hystrix相关配置
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000 #默认的连接超时时间1秒,若1秒没有返回数据,自动的触发降级逻辑
circuitBreaker:
enabled: true
requestVolumeThreshold: 5
errorThresholdPercentage: 10
sleepWindowInMilliseconds: 10000
5.2.3 注解
@EnableCircuitBreaker
//激活hytrix的web监控平台
5.2.4 使用案列
(1)基于 Feign 实现熔断降级,那么降级方法需要配置到 FeignClient 接口的实现类中。
@Component
public class ProductFeignClientCallBack implements ProductFeignClient {
/**
* 熔断降级的方法
*/
public Product findById(Long id) {
Product product = new Product();
product.setProductName("feign调用触发熔断降级方法");
return product;
}
}
(2) 修改 FeignClient 添加 hystrix 熔断
/**
* 声明需要调用的微服务名称
* @FeignClient
* * name : 服务提供者的名称
* * fallback : 配置熔断发生降级方法
* 实现类
*/
@FeignClient(name="service-product",fallback = ProductFeignClientCallBack.class)
public interface ProductFeignClient {
/**
* 配置需要调用的微服务接口
*/
@RequestMapping(value="/product/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable("id") Long id);
}
5.3 Hystrix Stream
5.3.1 依赖
<!--引入hystrix的监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
5.3.2 properties.yml配置
#hystrix对外暴露的所有端点
management:
endpoints:
web:
exposure:
include: '*'
5.3.3 注解
//激活hytrix的web监控平台
@EnableHystrixDashboard
5.3.4 使用案列
重启项目,访问 http://localhost:9003/actuator/hystrix.stream , 即可看到实时的监控数据。
5.4 Hystrix DashBoard Turbine
5.4.1 依赖
<!--引入hystrix的监控信息-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
5.4.2 properties.yml配置
无
5.4.3 注解
//激活hystrix
@EnableCircuitBreaker
//激活hytrix的web监控平台
@EnableHystrixDashboard
5.4.4 使用案列
http://localhost:9003/hystrix
5.5 Hystrix DashBoard Turbine
5.5.1 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
5.5.2 properties.yml配置
server:
port: 8031
spring:
application:
name: hystrix-turbine
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${server.port}
turbine:
# 要监控的微服务列表,多个用,分隔
appConfig: service-order
clusterNameExpression: "'default'"
5.5.3 注解
//trubin配置
@EnableTurbine
@EnableHystrixDashboard
5.5.4 使用案列
浏览器访问 http://localhost:8031/hystrix 展示 HystrixDashboard 。并在 url 位置输入 http://localhost:8031/turbine.stream ,动态根据 turbine.stream 数据展示多个微服务的监控数据。
6 springcloud注册中心——Sentinel
6.1 SentinelServer
6.1.1 获取 Sentinel 控制台
您可以从官方 网站中 下载最新版本的控制台 jar 包,下载地址如下:
https://github.com/alibaba/Sentinel/releases/download/1.6.3/sentinel-dashboard-1.6.3.jar
6.1.2 启动
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 - Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
6.1.3 访问
Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel 。
localhost:8080
6.2 Rest-SentinelClient
6.2.1 依赖
<!--springcloud整合的openFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
6.2.2 properties.yml配置
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 #sentinel控制台的请求地址
datasource: #加载本地资源配置
ds1:
file:
file: classpath:flowrule.json
data-type: json
rule-type: flow
eager: true #立即加载
6.2.3 注解
@SentinelRestTemplate
6.2.4 使用案列
(1)编写异常回调方法
public class ExceptionUtils {
/**
* 静态方法
* 返回值: SentinelClientHttpResponse
* 参数 : request , byte[] , clientRquestExcetion , blockException
*/
//限流熔断业务逻辑
public static SentinelClientHttpResponse handleBlock(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
return new SentinelClientHttpResponse("abc");
}
//异常降级业务逻辑
public static SentinelClientHttpResponse handleFallback(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
return new SentinelClientHttpResponse("def");
}
}
(2)在启动类RestTemplate中加载@SentinelRestTemplate即可
@SpringBootApplication
@EntityScan("cn.itcast.order.entity")
public class RestOrderApplication {
/**
* sentinel支持对restTemplate的服务调用使用sentinel方法.在构造
* RestTemplate对象的时候,只需要加载@SentinelRestTemplate即可
*
* 资源名:
* httpmethod:schema://host:port/path :协议、主机、端口和路径
* httpmethod:schema://host:port :协议、主机和端口
*
* @SentinelRestTemplate:
* 异常降级
* fallback : 降级方法
* fallbackClass : 降级配置类
* 限流熔断
* blockHandler
* blockHandlerClass
*/
@LoadBalanced
@Bean
@SentinelRestTemplate(fallbackClass = ExceptionUtils.class,fallback = "handleFallback",
blockHandler = "handleBlock" ,blockHandlerClass = ExceptionUtils.class
)
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RestOrderApplication.class,args);
}
}
6.3 Feign-SentinelClient
6.3.1 依赖
<!--feign对sentinel的支持-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
6.3.2 properties.yml配置
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 #sentinel控制台的请求地址
#激活sentinel的支持
feign:
sentinel:
enabled: true
6.3.3 注解
无
6.3.4 使用案列
(1 )配置 FeignClient
和使用 Hystrix 的方式基本一致,需要配置 FeignClient 接口以及通过 fallback 指定熔断降级方法
/**
* 声明需要调用的微服务名称
* @FeignClient
* * name : 服务提供者的名称
* * fallback : 配置熔断发生降级方法
* 实现类
*/
@FeignClient(name="service-product",fallback = ProductFeignClientCallBack.class)
public interface ProductFeignClient {
/**
* 配置需要调用的微服务接口
*/
@RequestMapping(value="/product/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable("id") Long id);
}
( 2 )配置熔断方法
@Component
public class ProductFeignClientCallBack implements ProductFeignClient {
/**
* 熔断降级的方法
*/
public Product findById(Long id) {
Product product = new Product();
product.setProductName("feign调用触发熔断降级方法");
return product;
}
}
7 springcloud网关——zuul
7.1 zuul
7.1.1 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
7.1.2 properties.yml配置
server:
port: 8080 #端口
spring:
application:
name: api-zuul-server #服务名称
##路由配置方式一-----通过url简单配置
#zuul:
# routes:
# #已商品微服务
# product-service: #路由id,随便写
# path: /product-service/** #映射路径 #localhost:8080/product-service/sxxssds
# url: http://127.0.0.1:9001 #映射路径对应的实际微服务url地址
##路由配置方式二-----通过ServerID从Euraka拉取服务
#zuul:
# routes:
# #已商品微服务
# product-service: #路由id,随便写
# path: /product-service/** #映射路径 #localhost:8080/product-service/sxxssds
# serviceId: service-product #配置转发的微服务的服务名称
##路由配置方式一-----通过ServerID从Euraka拉取服务
zuul:
routes:
#已商品微服务
#如果路由id 和 对应的微服务的serviceId一致的话
service-product: /product-service/**
#zuul中的默认路由配置
#如果当前的微服务名称 service-product , 默认的请求映射路径 /service-product/**
# /service-order/
#配置Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true #使用ip地址注册
7.1.3 注解
//开启zuul网关功能
@EnableZuulProxy
//eureka的服务发现
@EnableDiscoveryClient
7.1.4 使用案列
服务端接收客户端请求,验证是否合法在进行转发。
/**
* 自定义的zuul过滤器
* 继承抽象父类
*/
@Component
public class LoginFilter extends ZuulFilter {
/**
* 定义过滤器类型
* pre
* routing
* post
* error
*/
@Override
public String filterType() {
return "pre";
}
/**
* 指定过滤器的执行顺序
* 返回值越小,执行顺序越高
*/
@Override
public int filterOrder() {
return 1;
}
/**
* 当前过滤器是否生效
* true : 使用此过滤器
* flase : 不使用此过滤器
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 指定过滤器中的业务逻辑
* 身份认证:
* 1.所有的请求需要携带一个参数 : access-token
* 2.获取request请求
* 3.通过request获取参数access-token
* 4.判断token是否为空
* 4.1 token==null : 身份验证失败
* 4.2 token!=null : 执行后续操作
* 在zuul网关中,通过RequestContext的上下问对象,可以获取对象request对象
*/
@Override
public Object run() throws ZuulException {
//System.out.println("执行了过滤器");
//1.获取zuul提供的上下文对象RequestContext
RequestContext ctx = RequestContext.getCurrentContext();
//2.从RequestContext中获取request
HttpServletRequest request = ctx.getRequest();
//3.获取请求参数access-token
String token = request.getParameter("access-token");
//4.判断
if (token ==null) {
//4.1 如果token==null ,拦截请求,返回认证失败
ctx.setSendZuulResponse(false); // 拦截请求
ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
//4.2 如果token!=null ,继续后续操作
return null;
}
}
8 springcloud网关——Gateway
8.1 Gateway
8.1.1 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
8.1.2 properties.yml配置
spring:
application:
name: api-gateway-server #服务名称
redis:
host: localhost
pool: 6379
database: 0
cloud: #配置SpringCloudGateway的路由
gateway:
routes: #路由ID,路由到微服务的uri,断言(判断条件)
- id: order-service
uri: lb://service-order #从Eureka注册中心拉取服务
# uri: 127.0.0.1:9002 #简单路由配置
predicates:
- Path=/order-service/**
filters: #路径从写过滤器
- RewritePath=/order-service/(?<segment>.*), /$\{segment}
- id: product-service
uri: lb://service-product
# uri: 127.0.0.1:9001 #简单路由配置
predicates:
- Path=/product-service/**
filters:
- name: RequestRateLimiter #基于rides的配置
args:
# 使用SpEL从容器中获取对象
key-resolver: '#{@pathKeyResolver}'
# 令牌桶每秒填充平均速率
redis-rate-limiter.replenishRate: 1
# 令牌桶的上限
redis-rate-limiter.burstCapacity: 3
- RewritePath=/product-service/(?<segment>.*), /$\{segment}
discovery: #简化路由配置方式
locator:
enabled: true #开启根据服务名称自动转发
lower-case-service-id: true #微服务名称已小写形式呈现
# RequestRateLimiter : 使用限流过滤器,是springcloud gateway提供的
# 参数 replenishRate : 向令牌桶中填充的速率
# burstCapacity :令牌桶的容量
8.1.3 注解
无
8.1.4 使用案列
全局过滤器
/**
* 自定义一个全局过滤器
* 实现 globalfilter , ordered接口
*/
//@Component
public class LoginFilter implements GlobalFilter,Ordered {
/**
* 执行过滤器中的业务逻辑
* 对请求参数中的access-token进行判断
* 如果存在此参数:代表已经认证成功
* 如果不存在此参数 : 认证失败.
* ServerWebExchange : 相当于请求和响应的上下文(zuul中的RequestContext)
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("执行了自定义的全局过滤器");
//1.获取请求参数access-token
String token = exchange.getRequest().getQueryParams().getFirst("access-token");
//2.判断是否存在
if(token == null) {
//3.如果不存在 : 认证失败
System.out.println("没有登录");
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete(); //请求结束
}
//4.如果存在,继续执行
return chain.filter(exchange); //继续向下执行
}
/**
* 指定过滤器的执行顺序 , 返回值越小,执行优先级越高
*/
@Override
public int getOrder() {
return 0;
}
}
局部过滤器
基本限流
@Configuration
public class KeyResolverConfiguration {
/**
* 编写基于请求路径的限流规则
* //abc
* //基于请求ip 127.0.0.1
* //基于参数
*/
@Bean
public KeyResolver pathKeyResolver() {
//自定义的KeyResolver
return new KeyResolver() {
/**
* ServerWebExchange :
* 上下文参数
*/
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just( exchange.getRequest().getPath().toString());
}
};
}
/**
* 基于请求参数的限流
*
* 请求 abc ? userId=1
*/
// @Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getQueryParams().getFirst("userId")
// 基于请求ip的限流
// exchange.getRequest().getHeaders().getFirst("X-Forwarded-For")
);
}
}
sentinel限流
/**
* sentinel限流的配置
*/
@Configuration
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
/**
* 配置限流的异常处理器:SentinelGatewayBlockExceptionHandler
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
/**
* 配置限流过滤器
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
/**
* 配置初始化的限流参数
* 用于指定资源的限流规则.
* 1.资源名称 (路由id)
* 2.配置统计时间
* 3.配置限流阈值
*/
@PostConstruct
public void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("product-service")
.setCount(1)
.setIntervalSec(1)
);
rules.add(new GatewayFlowRule("product_api")
.setCount(1).setIntervalSec(1)
);
GatewayRuleManager.loadRules(rules);
}
/**
* 自定义API限流分组
* 1.定义分组
* 2.对小组配置限流规则
*/
@PostConstruct
private void initCustomizedApis() {
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition api1 = new ApiDefinition("product_api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/product-service/product/**"). //已/product-service/product/开都的所有url
setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
ApiDefinition api2 = new ApiDefinition("order_api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/order-service/order")); //完全匹配/order-service/order 的url
}});
definitions.add(api1);
definitions.add(api2);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
/**
* 自定义限流处理器
*/
@PostConstruct
public void initBlockHandlers() {
BlockRequestHandler blockHandler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
Map map = new HashMap();
map.put("code",001);
map.put("message","不好意思,限流啦");
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(map));
}
};
GatewayCallbackManager.setBlockHandler(blockHandler);
}
}