Browse Source

网关动态路由

by su 3 years ago
parent
commit
b7698db8c3

+ 2 - 1
4dkankan-center-scene/src/main/java/com/fdkankan/scene/SceneApplication.java

@@ -5,13 +5,14 @@ import com.fdkankan.common.util.StrExtUtil;
 import com.fdkankan.scene.dto.TestDto;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 
-@SpringBootApplication
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
 @RestController
 @EnableDiscoveryClient
 public class SceneApplication {

+ 11 - 5
4dkankan-common/pom.xml

@@ -52,11 +52,17 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-webflux</artifactId>
         </dependency>
-<!--        <dependency>-->
-<!--            <groupId>org.mybatis.spring.boot</groupId>-->
-<!--            <artifactId>mybatis-spring-boot-starter</artifactId>-->
-<!--            <version>1.3.2</version>-->
-<!--        </dependency>-->
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>1.3.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.58</version>
+        </dependency>
 
 <!--        <dependency>-->
 <!--            <groupId>mysql</groupId>-->

+ 11 - 0
4dkankan-gateway/pom.xml

@@ -64,6 +64,17 @@
             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+
+        <!--nacos 客户端 配置中心-->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 2 - 1
4dkankan-gateway/src/main/java/com/fdkankan/gateway/GatewayApplication.java

@@ -2,9 +2,10 @@ package com.fdkankan.gateway;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 
-@SpringBootApplication
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
 @EnableDiscoveryClient
 public class GatewayApplication {
 

+ 111 - 0
4dkankan-gateway/src/main/java/com/fdkankan/gateway/config/DynamicRouteServiceImpl.java

@@ -0,0 +1,111 @@
+package com.fdkankan.gateway.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
+import org.springframework.cloud.gateway.route.RouteDefinition;
+import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
+import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ApplicationEventPublisherAware;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+/**
+ * 动态更新路由网关service
+ * 1)实现一个Spring提供的事件推送接口ApplicationEventPublisherAware
+ * 2)提供动态路由的基础方法,可通过获取bean操作该类的方法。该类提供新增路由、更新路由、删除路由,然后实现发布的功能。
+ */
+@Slf4j
+@Service
+public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
+    @Autowired
+    private RouteDefinitionWriter routeDefinitionWriter;
+    @Autowired
+    private RouteDefinitionLocator routeDefinitionLocator;
+
+    /**
+     * 发布事件
+     */
+    @Autowired
+    private ApplicationEventPublisher publisher;
+
+    @Override
+    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
+        this.publisher = applicationEventPublisher;
+    }
+
+    /**
+     * 删除路由
+     * @param id
+     * @return
+     */
+    public String delete(String id) {
+        try {
+            log.info("gateway delete route id {}",id);
+            this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
+            this.publisher.publishEvent(new RefreshRoutesEvent(this));
+            return "delete success";
+        } catch (Exception e) {
+            return "delete fail";
+        }
+    }
+
+    /**
+     * 更新路由
+     * @param definitions
+     * @return
+     */
+    public String updateList(List<RouteDefinition> definitions) {
+        log.info("gateway update route {}",definitions);
+        // 删除缓存routerDefinition
+        List<RouteDefinition> routeDefinitionsExits =  routeDefinitionLocator.getRouteDefinitions().buffer().blockFirst();
+        if (!CollectionUtils.isEmpty(routeDefinitionsExits)) {
+            routeDefinitionsExits.forEach(routeDefinition -> {
+                log.info("delete routeDefinition:{}", routeDefinition);
+                delete(routeDefinition.getId());
+            });
+        }
+        definitions.forEach(definition -> {
+            updateById(definition);
+        });
+        return "success";
+    }
+
+    /**
+     * 更新路由
+     * @param definition
+     * @return
+     */
+    public String updateById(RouteDefinition definition) {
+        try {
+            log.info("gateway update route {}",definition);
+            this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
+        } catch (Exception e) {
+            return "update fail,not find route  routeId: "+definition.getId();
+        }
+        try {
+            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
+            this.publisher.publishEvent(new RefreshRoutesEvent(this));
+            return "success";
+        } catch (Exception e) {
+            return "update route fail";
+        }
+    }
+
+    /**
+     * 增加路由
+     * @param definition
+     * @return
+     */
+    public String add(RouteDefinition definition) {
+        log.info("gateway add route {}",definition);
+        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
+        this.publisher.publishEvent(new RefreshRoutesEvent(this));
+        return "success";
+    }
+}
+

+ 99 - 0
4dkankan-gateway/src/main/java/com/fdkankan/gateway/config/DynamicRouteServiceImplByNacos.java

@@ -0,0 +1,99 @@
+package com.fdkankan.gateway.config;
+
+import com.alibaba.fastjson.JSON;
+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.cloud.gateway.route.RouteDefinition;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+
+/**
+ *
+ * 通过nacos下发动态路由配置,监听Nacos中gateway-route配置
+ *
+ */
+@Component
+@Slf4j
+@DependsOn({"gatewayConfig"}) // 依赖于gatewayConfig bean
+public class DynamicRouteServiceImplByNacos {
+
+    @Autowired
+    private DynamicRouteServiceImpl dynamicRouteService;
+
+
+    private ConfigService configService;
+
+    @PostConstruct
+    public void init() {
+        log.info("gateway route init...");
+        try{
+            configService = initConfigService();
+            if(configService == null){
+                log.warn("initConfigService fail");
+                return;
+            }
+            String configInfo = configService.getConfig(GatewayConfig.NACOS_ROUTE_DATA_ID, GatewayConfig.NACOS_ROUTE_GROUP, GatewayConfig.DEFAULT_TIMEOUT);
+            log.info("获取网关当前配置:\r\n{}",configInfo);
+            List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
+            for(RouteDefinition definition : definitionList){
+                log.info("update route : {}",definition.toString());
+                dynamicRouteService.add(definition);
+            }
+        } catch (Exception e) {
+            log.error("初始化网关路由时发生错误",e);
+        }
+        dynamicRouteByNacosListener(GatewayConfig.NACOS_ROUTE_DATA_ID,GatewayConfig.NACOS_ROUTE_GROUP);
+    }
+
+    /**
+     * 监听Nacos下发的动态路由配置
+     * @param dataId
+     * @param group
+     */
+    public void dynamicRouteByNacosListener (String dataId, String group){
+        try {
+            configService.addListener(dataId, group, new Listener()  {
+                @Override
+                public void receiveConfigInfo(String configInfo) {
+                    log.info("进行网关更新:\n\r{}",configInfo);
+                    List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
+                    log.info("update route : {}",definitionList.toString());
+                    dynamicRouteService.updateList(definitionList);
+                }
+                @Override
+                public Executor getExecutor() {
+                    log.info("getExecutor\n\r");
+                    return null;
+                }
+            });
+        } catch (NacosException e) {
+            log.error("从nacos接收动态路由配置出错!!!",e);
+        }
+    }
+
+    /**
+     * 初始化网关路由 nacos config
+     * @return
+     */
+    private ConfigService initConfigService(){
+        try{
+            Properties properties = new Properties();
+            properties.setProperty("serverAddr",GatewayConfig.NACOS_SERVER_ADDR);
+            properties.setProperty("namespace",GatewayConfig.NACOS_NAMESPACE);
+            return configService= NacosFactory.createConfigService(properties);
+        } catch (Exception e) {
+            log.error("初始化网关路由时发生错误",e);
+            return null;
+        }
+    }
+}
+

+ 39 - 0
4dkankan-gateway/src/main/java/com/fdkankan/gateway/config/GatewayConfig.java

@@ -0,0 +1,39 @@
+package com.fdkankan.gateway.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class GatewayConfig {
+
+    public static final long DEFAULT_TIMEOUT = 30000;
+
+    public static String NACOS_SERVER_ADDR;
+
+    public static String NACOS_NAMESPACE;
+
+    public static String NACOS_ROUTE_DATA_ID;
+
+    public static String NACOS_ROUTE_GROUP;
+
+    @Value("${spring.cloud.nacos.config.server-addr}")
+    public void setNacosServerAddr(String nacosServerAddr){
+        NACOS_SERVER_ADDR = nacosServerAddr;
+    }
+
+    @Value("${spring.cloud.nacos.config.namespace}")
+    public void setNacosNamespace(String nacosNamespace){
+        NACOS_NAMESPACE = nacosNamespace;
+    }
+
+    @Value("${nacos.gateway.route.config.data-id}")
+    public void setNacosRouteDataId(String nacosRouteDataId){
+        NACOS_ROUTE_DATA_ID = nacosRouteDataId;
+    }
+
+    @Value("${nacos.gateway.route.config.group}")
+    public void setNacosRouteGroup(String nacosRouteGroup){
+        NACOS_ROUTE_GROUP = nacosRouteGroup;
+    }
+
+}

+ 0 - 14
4dkankan-gateway/src/main/resources/application.yml

@@ -1,14 +0,0 @@
-spring:
-  cloud:
-    gateway:
-      routes:
-        - id: route-center-scene
-          uri: lb://4dkankan-center-scene
-          predicates:
-            - Path=/test/*
-    nacos:
-      discovery:
-        server-addr: 192.168.0.47:8848
-  data:
-    mongodb:
-      uri: "mongodb://localhost:27017/test"

+ 0 - 2
4dkankan-gateway/src/main/resources/bootstrap.properties

@@ -1,2 +0,0 @@
-server.port=8080
-spring.application.name=4dkankan-gateway

+ 23 - 0
4dkankan-gateway/src/main/resources/bootstrap.yml

@@ -0,0 +1,23 @@
+server:
+  port: 8080
+spring:
+  application:
+    name: 4dkankan-gateway
+  cloud:
+    nacos:
+      discovery:
+        server-addr: 192.168.0.47:8848
+        namespace: bb2d9a01-711a-4f5e-b8ea-25ab821c145a
+      config:
+        namespace: bb2d9a01-711a-4f5e-b8ea-25ab821c145a
+        server-addr: 192.168.0.47:8848
+    data:
+      mongodb:
+      uri: "mongodb://localhost:27017/test"
+
+nacos:
+  gateway:
+    route:
+      config:
+        data-id: route-center-scene
+        group: DEFAULT_GROUP