北极星Polaris+Gateway动态网关配置!

时间:2022-11-25 17:14:59

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gton</groupId>
    <artifactId>cloud</artifactId>
    <packaging>pom</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <modules>
        <module>gateway</module>
        <module>usermanager</module>
        <module>commodity</module>
        <module>back-stage-management</module>
        <module>common</module>
    </modules>
    <name>cloud</name>
    <description>Spring Cloud Tencent +北极星(服务管理 流量管理 故障容错 配置管理) 微服务架构系统</description>

    <properties>
        <java.version>11</java.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-cloud-tencent-version>1.7.0-2021.0.3</spring-cloud-tencent-version>
        <spring-cloud-dependencies-version>2021.0.3</spring-cloud-dependencies-version>
        <projectlombok-version>1.18.16</projectlombok-version>
        <spring-boot.version>2.6.9</spring-boot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.tencent.cloud</groupId>
                <artifactId>spring-cloud-tencent-dependencies</artifactId>
                <version>${spring-cloud-tencent-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud-dependencies-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.16</version>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

gateway导入pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud</artifactId>
        <groupId>com.gton</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>gateway</artifactId>

    <properties>
        <fastJson-version>2.0.18</fastJson-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!--网关路由-->
        <dependency>
            <groupId>com.tencent.cloud</groupId>
            <artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
        </dependency>

        <!--服务注册与发现-->
        <dependency>
            <groupId>com.tencent.cloud</groupId>
            <artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
        </dependency>

        <!--服务限流-->
        <dependency>
            <groupId>com.tencent.cloud</groupId>
            <artifactId>spring-cloud-starter-tencent-polaris-ratelimit</artifactId>
        </dependency>


        <!--北极星配置中心-->
        <dependency>
            <groupId>com.tencent.cloud</groupId>
            <artifactId>spring-cloud-starter-tencent-polaris-config</artifactId>
        </dependency>

        <!--北极星熔断-->
        <dependency>
            <groupId>com.tencent.cloud</groupId>
            <artifactId>spring-cloud-starter-tencent-polaris-circuitbreaker</artifactId>
        </dependency>

        <!--负载均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

        <!-- bootstrap*启动配置读取 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-circuitbreaker-spring-retry</artifactId>
        </dependency>


        <!--使用gateway做网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>${fastJson-version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>


</project>

网关配置:

spring:
  application:
    name: gateway
  cloud:
    gateway:
      discovery:
        locator:
          # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
          enabled: true
    polaris:
      address: grpc://localhost:8091 #北极星注册中心地址
      namespace: polaris-cloud-market #北极星注册中心的使用命名空间,自定义
      config:
        auto-refresh: true #当配置发布后,动态刷新
        address:  grpc://localhost:8093  # 当配置中心和 注册中心地址不一致时可以选择,否着可以不填
        groups:
          - name: gatewayOnly #读取的文件所在分组
            files: ["router.properties","myconfig.yaml"]  #读取的文件名

北极星控制台配置
北极星Polaris+Gateway动态网关配置!

gateway网关的路由操作类:

package com.gton.service;


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;

/**
 * @description:动态更新路由网关service
 * @author: GuoTong
 * @createTime: 2022-10-05 22:24
 * @since JDK 1.8 OR 11
 **/
@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(this::updateById);
        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";
    }
}

监听路由变化

package com.gton.listener;

import com.alibaba.fastjson2.JSONObject;
import com.gton.service.DynamicRouteServiceImpl;
import com.tencent.cloud.polaris.config.annotation.PolarisConfigKVFileChangeListener;
import com.tencent.cloud.polaris.config.listener.ConfigChangeEvent;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.configuration.api.core.ChangeType;
import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.util.*;

/**
 * @description: 监听Polaris的配置更新
 * @author: GuoTong
 * @createTime: 2022-11-24 22:25
 * @since JDK 1.8 OR 11
 **/
@Component
@Slf4j
@SuppressWarnings("all")
public class ListenerPolaris {

    @Autowired
    private DynamicRouteServiceImpl dynamicRouteService;


    /**
     * PolarisConfigKVFileChangeListener Example .
     * 监听北极星中心变更路由
     *
     * @param event instance of {@link ConfigChangeEvent}
     */
    @PolarisConfigKVFileChangeListener(interestedKeyPrefixes = "routes")
    public void onChange(ConfigChangeEvent event) {
        // 封装需要更新的路由规则数据
        List<RouteDefinition> routeUpdates = new ArrayList<>();
        // 获取配置修改的所有key
        Set<String> changedKeys = event.changedKeys();
        // 保留已经处理的
        Set<String> intIndex = new HashSet<>();
        for (String changedKey : changedKeys) {
            // 获取修改的实体
            ConfigPropertyChangeInfo changeInfo = event.getChange(changedKey);
            if (changeInfo.getChangeType() == ChangeType.ADDED) {
                String newValue = changeInfo.getNewValue();
                // 添加新路由
                addNewRule(routeUpdates, newValue);

            }
            // 删除老路由(弃用)
            if (changeInfo.getChangeType() == ChangeType.DELETED) {
                String newValue = changeInfo.getNewValue();
                JSONObject jsonObject = JSONObject.parseObject(newValue);
                String id = jsonObject.getString("id");
                dynamicRouteService.delete(id);
            }
            if (CollectionUtils.isNotEmpty(routeUpdates)) {
                routeUpdates.forEach(item -> dynamicRouteService.add(item));
            }

        }

    }

    /**
     * Description: 添加新路由
     *
     * @param routeUpdates
     * @param changeInfo
     * @author: GuoTong
     * @date: 2022-11-25 15:32:59
     * @return:void
     */
    public void addNewRule(List<RouteDefinition> routeUpdates, String newValue) {

        RouteDefinition routeDefinition = new RouteDefinition();
        JSONObject jsonObject = JSONObject.parseObject(newValue);
        routeDefinition.setId(jsonObject.getString("id"));
        routeDefinition.setUri(URI.create(jsonObject.getString("uri")));
        List<PredicateDefinition> predicates = routeDefinition.getPredicates();
        String predicates1 = jsonObject.getString("predicates");
        if (predicates1.contains(";")) {
            String[] split = predicates1.split(";");
            for (String vars : split) {
                String[] var3 = vars.split("=");
                PredicateDefinition predicateDefinition = new PredicateDefinition();
                predicateDefinition.setName(var3[0]);
                Map<String, String> args = predicateDefinition.getArgs();
                args.put(var3[0], var3[1]);
                predicates.add(predicateDefinition);
            }
        } else {
            String[] split = predicates1.split("=");
            PredicateDefinition predicateDefinition = new PredicateDefinition();
            predicateDefinition.setName(split[0]);
            Map<String, String> args = predicateDefinition.getArgs();
            args.put(split[0], split[1]);
            predicates.add(predicateDefinition);
        }

        List<FilterDefinition> filters = routeDefinition.getFilters();
        String var6 = jsonObject.getString("filters");
        if (var6.contains(";")) {
            String[] var7 = var6.split(";");
            for (String var8 : var7) {
                String[] split = var8.split("=");
                FilterDefinition filterDefinition = new FilterDefinition();
                filterDefinition.setName(split[0]);
                Map<String, String> args = filterDefinition.getArgs();
                args.put(split[0], split[1]);
                filters.add(filterDefinition);
            }

        } else {
            String[] split = var6.split("=");
            FilterDefinition filterDefinition = new FilterDefinition();
            filterDefinition.setName(split[0]);
            Map<String, String> args = filterDefinition.getArgs();
            args.put(split[0], split[1]);
            filters.add(filterDefinition);
        }
        routeUpdates.add(routeDefinition);
    }

}

初始化读取配置

package com.gton.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @description: 读取北极星配置路由
 * @author: GuoTong
 * @createTime: 2022-11-25 15:55
 * @since JDK 1.8 OR 11
 **/
@ConfigurationProperties(prefix = "routes")
@Component
@Data
public class ReadRouterConfig {

    /**
     * Description:  网关路由动态配置
     *
     * @author: GuoTong
     * @date: 2022-11-25 16:08:23
     * @param rule
     * @return:
     */
    private List<String> rule;

}

启动加载配置问阿金

package com.gton.config;

import com.gton.listener.ListenerPolaris;
import com.gton.service.DynamicRouteServiceImpl;
import com.tencent.polaris.api.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * @program: PersonalDesign
 * @description: 项目一启动就执行
 **/
@Slf4j
@Component
@Order(value = 1)
public class MyApplicationRunner implements ApplicationRunner {

    @Autowired
    private ReadRouterConfig readRouterConfig;

    @Autowired
    private ListenerPolaris listenerPolaris;

    @Autowired
    private DynamicRouteServiceImpl dynamicRouteService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("开始网关路由配置加载。。。。。。");
        // 读取北极星上的配置信息
        List<String> rule = readRouterConfig.getRule();
        List<RouteDefinition> routeUpdates = new ArrayList<>();
        // 北极星上的配置处理
        rule.forEach(item -> listenerPolaris.addNewRule(routeUpdates, item));
        if (log.isDebugEnabled()) {
            log.debug("加载的路由配置是->{}", routeUpdates);
        }
        // 启动完成注册相关路由配置
        if (CollectionUtils.isNotEmpty(routeUpdates)) {
            routeUpdates.forEach(item -> dynamicRouteService.add(item));
        }
        log.info("网关路由配置加载结束。。。。。。");
    }
}

到此结束!!!!