添加依赖:
<!-- 网关需要从eureka注册中心上去发现微服务来进行节点的路由 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
1,负载均衡到某一服务集群中的某一节点
更新application.yml配置,
spring
cloud:
gateway:
routes:
- id: lb_route
predicates:
- Path=/lb/**
filters:
- StripPrefix=1
uri: lb://order-service #网关路由会转发到服务ID为order-service的服务,lb代表从注册中心获取服务.
discovery:
locator:
enabled: true # 默认为false,设为true便开启通过服务中心的自动根据 serviceId 创建路由的功能。 路由的路径对应会使用大写ID。
lower-case-service-id: true
order-service节点起两个服务节点,一个8082,一个8085
代码如下:--------------
@RefreshScope
@RestController
public class ConfigController {
@Value("${name}")
private String name;
@Value("${server.port}")
private String serverPort;
@GetMapping("/getName")
public String getName(){
return "从配置中心获取的name值为:"+ name + ", serverPort:" + serverPort;
}
}
访问:http://localhost:8080/lb/getName
2,通过Redis做限流
spring
cloud:
gateway:
routes:
- id: ratelimiter_route
predicates:
- Path=/ratelimiter/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
deny-empty-key: true
keyResolver: '#{@ipAddressKeyResolver}' # 用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。
redis-rate-limiter.replenishRate: 1 # 令牌桶每秒填充平均速率
redis-rate-limiter.burstCapacity: 2 # 令牌桶总容量2
uri: lb://order-service
discovery:
locator:
enabled: true # 默认为false,设为true便开启通过服务中心的自动根据 serviceId 创建路由的功能。 路由的路径对应会使用大写ID。
lower-case-service-id: true
/**
* 使用IP地址的维度进行限流
*/
@Component
public class IpAddressKeyResolver implements KeyResolver{
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
访问:http://localhost:8080/ratelimiter/getName
访问速度加快的话,就会出现下面最后一个图示:
3,动态路由
获取网关中所有的路由:http://localhost:8080/actuator/gateway/routes/
/**
* 动态路由(新增,删除路由)
* Spring Gateway默认是通过内存(InMemoryRouteDefinitionRepository)实现的,但是gateway项目的重启会导致新增或删除的路由失效,
* 所以这里采用redis实现动态路由
*/
@Component
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
private final static String GATEWAY_ROUTE_KEY="gateway_dynamic_route";
@Autowired
RedisTemplate<String,String> redisTemplate;
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
List<RouteDefinition> routeDefinitionList=new ArrayList<>();
redisTemplate.opsForHash().values(GATEWAY_ROUTE_KEY).stream().forEach(route->{
routeDefinitionList.add(JSON.parseObject(route.toString(),RouteDefinition.class));
});
return Flux.fromIterable(routeDefinitionList);
}
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(routeDefinition -> {
redisTemplate.opsForHash().put(GATEWAY_ROUTE_KEY,routeDefinition.getId(),JSON.toJSONString(routeDefinition));
return Mono.empty();
});
}
@Override
public Mono<Void> delete(Mono<String> routeId) {
return routeId.flatMap(id->{
if(redisTemplate.opsForHash().hasKey(GATEWAY_ROUTE_KEY,id)){
redisTemplate.opsForHash().delete(GATEWAY_ROUTE_KEY,id);
return Mono.empty();
}
return Mono.defer(()->Mono.error(new Exception("routeDefinition not found:"+routeId)));
});
}
}
官网示例:
新增
最后调用:http://localhost:8080/baidu 成功跳转到了baidu.com !完美!
最后可以看下删除操作
这里新增和删除,已经自动更新了缓存。 是CachingRouteLocator类中实现了ApplicationListener
/**
* 会自动更新缓存
*/
@Override
public void onApplicationEvent(RefreshRoutesEvent event) {
try {
fetch().collect(Collectors.toList()).subscribe(list -> Flux.fromIterable(list)
.materialize().collect(Collectors.toList()).subscribe(signals -> {
applicationEventPublisher
.publishEvent(new RefreshRoutesResultEvent(this));
cache.put(CACHE_KEY, signals);
}, throwable -> handleRefreshError(throwable)));
}
catch (Throwable e) {
handleRefreshError(e);
}
}
---如果新增和删除没有更新缓存的话,那么需要调用/actuator/gateway/refresh进行刷新:
进行调用: