Spring Cloud Gateway实战之三:动态路由,linux入门基础教程视频

import com.fasterxml.jackson.core.type.TypeReference;

import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.extern.slf4j.Slf4j;

import org.springframework.cloud.gateway.event.RefreshRoutesEvent;

import org.springframework.cloud.gateway.route.RouteDefinition;

import org.springframework.cloud.gateway.route.RouteDefinitionWriter;

import org.springframework.context.ApplicationEventPublisher;

import org.springframework.util.StringUtils;

import reactor.core.publisher.Mono;

import java.util.ArrayList;

import java.util.List;

@Slf4j

public class RouteOperator {

private ObjectMapper objectMapper;

private RouteDefinitionWriter routeDefinitionWriter;

private ApplicationEventPublisher applicationEventPublisher;

private static final List routeList = new ArrayList<>();

public RouteOperator(ObjectMapper objectMapper, RouteDefinitionWriter routeDefinitionWriter, ApplicationEventPublisher applicationEventPublisher) {

this.objectMapper = objectMapper;

this.routeDefinitionWriter = routeDefinitionWriter;

this.applicationEventPublisher = applicationEventPublisher;

}

/**

  • 清理集合中的所有路由,并清空集合

*/

private void clear() {

// 全部调用API清理掉

routeList.stream().forEach(id -> routeDefinitionWriter.delete(Mono.just(id)).subscribe());

// 清空集合

routeList.clear();

}

/**

  • 新增路由

  • @param routeDefinitions

*/

private void add(List routeDefinitions) {

try {

routeDefinitions.stream().forEach(routeDefinition -> {

routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();

routeList.add(routeDefinition.getId());

});

} catch (Exception exception) {

exception.printStackTrace();

}

}

/**

  • 发布进程内通知,更新路由

*/

private void publish() {

applicationEventPublisher.publishEvent(new RefreshRoutesEvent(routeDefinitionWriter));

}

/**

  • 更新所有路由信息

  • @param configStr

*/

public void refreshAll(String configStr) {

log.info(“start refreshAll : {}”, configStr);

// 无效字符串不处理

if (!StringUtils.hasText(configStr)) {

log.error("in

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

valid string for route config");

return;

}

// 用Jackson反序列化

List routeDefinitions = null;

try {

routeDefinitions = objectMapper.readValue(configStr, new TypeReference<List>(){});

} catch (JsonProcessingException e) {

log.error(“get route definition from nacos string error”, e);

}

// 如果等于null,表示反序列化失败,立即返回

if (null==routeDefinitions) {

return;

}

// 清理掉当前所有路由

clear();

// 添加最新路由

add(routeDefinitions);

// 通过应用内消息的方式发布

publish();

log.info(“finish refreshAll”);

}

}

  • 做一个配置类RouteOperatorConfig.java,将实例化后的RouteOperator注册到spring环境中:

package com.bolingcavalry.gateway.config;

import com.bolingcavalry.gateway.service.RouteOperator;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.cloud.gateway.route.RouteDefinitionWriter;

import org.springframework.context.ApplicationEventPublisher;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

@Configuration

public class RouteOperatorConfig {

@Bean

public RouteOperator routeOperator(ObjectMapper objectMapper,

RouteDefinitionWriter routeDefinitionWriter,

ApplicationEventPublisher applicationEventPublisher) {

return new RouteOperator(objectMapper,

routeDefinitionWriter,

applicationEventPublisher);

}

}

  • 最后是nacos的监听类RouteConfigListener,可见关键技术点是ConfigService.addListener,用于添加监听,里面就是配置发生变化后更新路由的逻辑,另外还有很重要的一步:立即调用getConfig方法取得当前配置,刷新当前进程的路由配置:

package com.bolingcavalry.gateway.service;

import com.alibaba.nacos.api.NacosFactory;

import com.alibaba.nacos.api.config.ConfigService;

import com.alibaba.nacos.api.config.listener.Listener;

import com.alibaba.nacos.api.exception.NacosException;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

import java.util.concurrent.Executor;

@Component

@Slf4j

public class RouteConfigListener {

private String dataId = “gateway-json-routes”;

private String group = “DEFAULT_GROUP”;

@Value("${spring.cloud.nacos.config.server-addr}")

private String serverAddr;

@Autowired

RouteOperator routeOperator;

@PostConstruct

public void dynamicRouteByNacosListener() throws NacosException {

ConfigService configService = NacosFactory.createConfigService(serverAddr);

// 添加监听,nacos上的配置变更后会执行

configService.addListener(dataId, group, new Listener() {

public void receiveConfigInfo(String configInfo) {

// 解析和处理都交给RouteOperator完成

routeOperator.refreshAll(configInfo);

}

public Executor getExecutor() {

return null;

}

});

// 获取当前的配置

String initConfig = configService.getConfig(dataId, group, 5000);

// 立即更新

routeOperator.refreshAll(initConfig);

}

}

  • RouteConfigListener.java中还有一处要记下来,那就是dataId变量的值gateway-json-routes,这是nacos上配置文件的名字,稍后咱们在nacos上配置的时候会用到

  • 最后是平淡无奇的启动类:

package com.bolingcavalry.gateway;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class GatewayApplication {

public static void main(String[] args) {

SpringApplication.run(GatewayApplication.class,args);

}

}

  • 编码完成了,接下来在nacos上增加两个配置;

  • 第一个配置名为gateway-dynamic-by-nacos,内容如下:

server:

port: 8086

暴露端点

management:

endpoints:

web:

exposure:

include: ‘*’

endpoint:

health:

show-details: always

  • 第二个配置名为gateway-json-routes,格式要选择JSON,可见只有一个路由(IP+端口那个),另一个用服务名作为URL的路由先不配上去,稍后用来验证动态增加能不能立即生效:

[

{

“id”: “path_route_addr”,

“uri”: “http://127.0.0.1:8082”,

“predicates”:[

{

“name”: “Path”,

“args”: {

“pattern”: “/hello/**”

}

}

]

}

]

  • 至此,咱们已经完成了开发工作,接下来验证动态路由是否能达到预期效果,我这里用的客户端工具是postman

验证

  • 确保nacos、provider-hello、gateway-dynamic-by-nacos等服务全部启动:

在这里插入图片描述

  • 用postman访问http://127.0.0.1:8086/hello/str,可以正常访问到,证明Gateway应用已经从nacos顺利下载了路由:

在这里插入图片描述

  • 此时如果用访问http://127.0.0.1:8086/lbtest/str应该会失败,因为nacos上还没有配置这个path的路由,如下图,果然失败了:

在这里插入图片描述

  • 在nacos上修改配置项gateway-json-routes的内容,增加名为path_route_lb的路由配置,修改后完整的配置如下:

[

{

“id”: “path_route_addr”,

“uri”: “http://127.0.0.1:8082”,

“predicates”:[

{

“name”: “Path”,

“args”: {

“pattern”: “/hello/**”

}

}

]

}

,

{

“id”: “path_route_lb”,

“uri”: “lb://provider-hello”,

“predicates”:[

{

“name”: “Path”,

“args”: {

“pattern”: “/lbtest/**”

}

}

]

}

]

  • 点击右下角的发布按钮后,gateway-dynamic-by-nacos应用的控制台立即输出了以下内容,可见监听已经生效:

2021-08-15 19:39:45.883 INFO 18736 — [-127.0.0.1_8848] c.a.n.client.config.impl.ClientWorker : [fixed-127.0.0.1_8848] [polling-resp] config changed. dataId=gateway-json-routes, group=DEFAULT_GROUP

2021-08-15 19:39:45.883 INFO 18736 — [-127.0.0.1_8848] c.a.n.client.config.impl.ClientWorker : get changedGroupKeys:[gateway-json-routes+DEFAULT_GROUP]

2021-08-15 19:39:45.890 INFO 18736 — [-127.0.0.1_8848] c.a.n.client.config.impl.ClientWorker : [fixed-127.0.0.1_8848] [data-received] dataId=gateway-json-routes, group=DEFAULT_GROUP, tenant=null, md5=54fb76dcad838917818d0160ce2bd72f, content=[

{

“id”: “path_route_addr”,

“uri”: “http://127.0.0.1:8082”,

"predicates…, type=json

2021-08-15 19:39:45.891 INFO 18736 — [-127.0.0.1_8848] c.b.gateway.service.RouteOperator : start refreshAll : [

{

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值