【SpringCloudAlibaba专题】Springcloud gateway之分流、限流、熔断、动态路由(G版本)

Springcloud Gateway

在这里插入图片描述
Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。

一、实现服务的路由

引入相关pom依赖

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

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

做下简单配置

management:
  endpoints:
    web:
      exposure:
        include: '*' #打开endpoint
server:
  port: 18085
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      discovery:
        locator:
          lower-case-service-id: true  #gateway可以通过开启以下配置来打开根据服务的serviceId来匹配路由,默认是false大写
          enabled: true # 是否可以通过其他服务的serviceId来转发到具体的服务实例。默认为false
      routes:
        - id: service-hi
          uri: lb://service-hi # lb://serviceId
          predicates:
            - Path=/admin/service-hi/**  # 如果请求地址满足/service-hi/**,则转发到service-hi服务
          filters:
            - StripPrefix=2 # 去除请求url中的/admin/service-hi/
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # 使用nacos作为注册中心

启动service-hi、api-gateway服务,访问 http://localhost:18085/admin/service-hi/hello?name=123
在这里插入图片描述

不排除,有的喜欢用java config的方式去做路由,这里也给出案例,将上面路由配置注视掉,添加如下config,重启api-gateway服务,访问 http://localhost:18085/admin/service-hi/hello?name=123

@Configuration
public class RouterConfig {
    static final String prefix = "/admin";

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("SERVICE-FEIGN", r ->
                        r.path(prefix + "/service-hi/**").
                                filters(f -> f.rewritePath(prefix + "/service-hi/(?<remaining>.*)", "/$\\{remaining}"))
                                .uri("lb://service-hi"))
                .build();

    }

}

在这里插入图片描述

二、nacos动态配置是拉还是推呢?

上代码我们可以在启动类中写入一下的代码,在nacos配置groupId为test-gateway,group为test-group

public class ServiceHiApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(ServiceHiApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        ConfigService configService = NacosFactory.createConfigService("localhost:8848");//获取ConfigService
        configService.addListener("test-gateway", "test-group", new Listener() {
            @Override
            public void receiveConfigInfo(String configInfo) {
                System.out.println(configInfo);
            }

            @Override
            public Executor getExecutor() {
                return null;
            }
        });
    }
}

客户端是通过一个定时任务来检查自己监听的配置项的数据的,一旦服务端的数据发生变化时,客户端将会获取到最新的数据,并将最新的数据保存在一个 CacheData 对象中,然后会重新计算 CacheData 的 md5 属性的值,此时就会对该 CacheData 所绑定的 Listener 触发 receiveConfigInfo 回调。

博客参考: http://blog.didispace.com/nacos-yuanli-1/ 讲的比较详细,在此基础上又做了扩展,能不能动态刷新路由?

三、如何动态刷新路由

基于时间监听机制,我们可以动态刷新Springcloud gateway的RouteDefinition,提供一个服务类,主要用于通过代码的方式对路由进行更新。至于springboot事件监听,以后会有博客专门讲解,请持续关注。


@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher publisher;


    /**
     * 增加路由
     *
     * @param definition
     * @return
     */
    public String add(RouteDefinition definition) {
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }


    /**
     * 更新路由
     *
     * @param definition
     * @return
     */
    public String update(RouteDefinition definition) {
        try {
            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 id
     * @return
     */
    public String delete(String id) {
        try {
            this.routeDefinitionWriter.delete(Mono.just(id));
            return "delete success";
        } catch (Exception e) {
            e.printStackTrace();
            return "delete fail";
        }

    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }


}

还需要你个动态刷新监听,也就是我们上面讲到的代码,这里只需要做下简单的封装

@Component
public class DynamicRouteServiceImplByNacos {

    @Autowired
    private DynamicRouteServiceImpl dynamicRouteService;

    public DynamicRouteServiceImplByNacos() {

        dynamicRouteByNacosListener("test-gateway", "test-group");
    }

    /**
     * 监听Nacos Server下发的动态路由配置
     *
     * @param dataId
     * @param group
     */
    public void dynamicRouteByNacosListener(String dataId, String group) {
        try {
            ConfigService configService = NacosFactory.createConfigService("localhost:8848");
//            String content = configService.getConfig(dataId, group, 5000);
            configService.addListener(dataId, group, new Listener() {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    MyRoute myRoute = JSON.parseObject(configInfo, MyRoute.class);

                    if (!CollectionUtils.isEmpty(myRoute.getRouteDefinitionList())) {
                        myRoute.getRouteDefinitionList().forEach(i -> dynamicRouteService.update(i));
                    }
                }

                @Override
                public Executor getExecutor() {
                    return null;
                }
            });
        } catch (NacosException e) {
            //todo 提醒:异常自行处理此处省略
        }
    }

}

把之前所有配置路由信息都要注释掉,这里为了我们通过nacos,动态得去配置路由服务,启动api-gateway、service-feign、service-hi,在nacos配置groupId为test-gateway,group为test-group,里面配置了service-hi的路由配置,发布一下。即可看到可以路由到service-hi服务,这样就是实现了基于nacos的动态路由


{
    "routeDefinitionList": [
        {
            "filters": [
                {
                    "args": {
                        "_genkey_0": "1"
                    }, 
                    "name": "StripPrefix"
                }
            ], 
            "id": "service-hi", 
            "order": 0, 
            "predicates": [
                {
                    "args": {
                        "pattern": "/service-hi/**"
                    }, 
                    "name": "Path"
                }
            ], 
            "uri": "lb://service-hi"
        }, 
        {
            "filters": [ ], 
            "id": "jd_route", 
            "order": 0, 
            "predicates": [
                {
                    "args": {
                        "pattern": "/jd"
                    }, 
                    "name": "Path"
                }
            ], 
            "uri": "http://www.baidu.com"
        }
    ]
}

四、可以做限流么(TODO,请持续关注,有惊喜)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值