一:导入相关依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!---本地连接sentinel-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
二:创建bootstrap.yml文件
#默认端口
server:
port: 30000
#自定义参数
nacos:
server-addr: 127.0.0.1:40002
sentinel:
server-addr: 127.0.0.1:40008
spring:
main:
#支持名称相同的bean被覆盖
allow-bean-definition-overriding: true
#环境配置
profiles:
active: local
#name
application:
name: ljq-gateway
#nacos配置
cloud:
nacos:
discovery:
server-addr: ${nacos.server-addr} #注册中心
#不配置默认加载public的 配置加载自己命名空间
namespace: ${spring.profiles.active} #命名空间id
group: ${spring.profiles.active}
config:
server-addr: ${nacos.server-addr} #配置中心
group: ${spring.profiles.active} #分组 默认分组
file-extension: yaml #类型
namespace: ${spring.profiles.active} #命名空间id
#多个dataID加载多个配置文件
ext-config[0]:
data-id: application-common.yaml
group: ${spring.profiles.active} #公用分组
refresh: true #动态刷新
#sentinel
sentinel:
transport:
dashboard: ${sentinel.server-addr}
eager: true #开启客户端懒加载
datasource:
ds:
nacos:
server-addr: ${nacos.server-addr} #nacos连接
groupId: ${spring.profiles.active} #分组 默认分组
file-extension: json #类型
namespace: ${spring.profiles.active} #命名空间id
rule-type: flow #该参数是spring cloud alibaba升级到0.2.2之后增加的配置,用来定义存储的规则类型。所有的规则类型可查看枚举类:
dataId: ${spring.application.name}-sentinel
三:配置nacos相关内容
1.1:配置命名空间:
1.2:配置配置管理
1.3 配置限流规则:
四:配置gateway
package com.ljq.gateway.config;
import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.annotation.PostConstruct;
import java.util.*;
/**
* 配置gateway规则
*
* @author hxy_admin
*/
@Configuration
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
/**
* 网关配置
*
* @param viewResolversProvider
* @param serverCodecConfigurer
*/
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
/**
* 哨兵网关块异常处理程序
*
* @return
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
/**
* 哨兵网关过滤器
*
* @return
*/
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
/**
* 初始化
*/
@PostConstruct
public void doInit() {
//自定义限流规则Apis
initCustomizedApis();
//自定义的 API 定义分组
initGatewayRules();
//限流异常处理
initBlockHandler();
}
/**
* 限流异常处理
*/
private void initBlockHandler() {
BlockRequestHandler handler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
System.out.println(throwable);
Map<Object, Object> map = new HashMap<>();
map.put("code", "429");
map.put("message", "接口限流了");
map.put("data", null);
map.put("success", false);
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(map));
}
};
GatewayCallbackManager.setBlockHandler(handler);
}
/**
* 自定义限流规则Apis
*/
private void initCustomizedApis() {
Set<ApiDefinition> definitions = new HashSet<>();
//把不同服务的请求进行分组
ApiDefinition api1 = new ApiDefinition("ljq-provider-server-api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/api/provider/**")
//参数值的匹配策略,目前支持精确匹配(PARAM_MATCH_STRATEGY_EXACT)、子串匹配(PARAM_MATCH_STRATEGY_CONTAINS)和正则匹配(PARAM_MATCH_STRATEGY_REGEX)
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
ApiDefinition api2 = new ApiDefinition("ljq-consumers-server-api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/api/consumers/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
ApiDefinition api3 = new ApiDefinition("ljq-gateway-api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/api/login/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(api1);
definitions.add(api2);
definitions.add(api3);
//手动加载
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
/**
* 初始化网关规则
* GatewayFlowRule:网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
* resource:资源名称,可以是网关中的 route 名称或者用户自定义的API 分组名称。
* resourceMode:规则是针对 API Gateway 的route(RESOURCE_MODE_ROUTE_ID)还是用户在 Sentinel 中定义的API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是route。
* grade:限流指标维度,同限流规则的grade 字段。
* count:限流阈值
* intervalSec:统计时间窗口,单位是秒,默认是1 秒(目前仅对参数限流生效)。
* controlBehavior:流量整形的控制效果,同限流规则的 controlBehavior 字段,目前支持快速失败和匀速排队两种模式,默认是快速失败。
* burst:应对突发请求时额外允许的请求数目(目前仅对参数限流生效)。
* maxQueueingTimeoutMs:匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。
* paramItem:参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。其中的字段:
* parseStrategy:从请求中提取参数的策略,目前支持提取来源 IP(PARAM_PARSE_STRATEGY_CLIENT_IP)、Host(PARAM_PARSE_STRATEGY_HOST)、任意 Header(PARAM_PARSE_STRATEGY_HEADER)和任意 URL 参数(PARAM_PARSE_STRATEGY_URL_PARAM)四种模式。
* fieldName:若提取策略选择 Header 模式或 URL 参数模式,则需要指定对应的 header 名称或 URL 参数名称。
* pattern 和 matchStrategy:为后续参数匹配特性预留,目前未实现。
* 用户可以通过 GatewayRuleManager.loadRules(rules)手动加载网关规则,或通过 GatewayRuleManager.register2Property(property)注册动态规则源动态推送(推荐方式)。
* 自定义route纬度:
*/
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("ljq-provider-server-api")
.setCount(1) //限流阈值
.setIntervalSec(1) //统计时间窗口,单位是秒,默认是1 秒(目前仅对参数限流生效)。
.setBurst(2) //应对突发请求时额外允许的请求数目(目前仅对参数限流生效)。
);
rules.add(new GatewayFlowRule("ljq-consumers-server-api")
.setCount(1) //限流阈值
.setIntervalSec(1) //统计时间窗口,单位是秒,默认是1 秒(目前仅对参数限流生效)。
.setBurst(2) //应对突发请求时额外允许的请求数目(目前仅对参数限流生效)。
);
rules.add(new GatewayFlowRule("ljq-gateway-api")
.setCount(1)
.setIntervalSec(1)
.setBurst(2) //应对突发请求时额外允许的请求数目(目前仅对参数限流生效)。
);
//加载路由规则
GatewayRuleManager.loadRules(rules);
}
}
五:创建测试接口
package com.ljq.gateway.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api")
@RestController
public class TestController {
@SentinelResource(value = "login")
@GetMapping("/login")
public String fun(){
System.out.println("testD 测试RT");
return "登录成功!!!";
}
}
六:创建启动类即可.
注意事项:
1:限流规则参考官网:
https://sentinelguard.io/zh-cn/index.html
2: 2.1:nacos-win启动命令:
startup.cmd -m standalone
2.2:nacos-linux启动命令:
startup.sh -m standalone
2.3:账号:nacos 密码:nacos
3:3.1:sentinel win启动:
java -Dserver.port=40008 -Dcsp.sentinel.dashboard.server=localhost:40008 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
3.2:sentinel linux启动:
nohup java -Dserver.port=40008 -Dcsp.sentinel.dashboard.server=localhost:40008 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar >sentinel.log &
3.3:账号:sentinel 密码:sentinel