前言:

公司最近搭建新项目,需要用到SpringCloud Gateway,网关作为所有请求流量的入口,在实际生产环境中为了保证高可靠和高可用,
尽量避免重启,需要实现Spring Cloud Gateway动态路由配置。
公司的配置中心为携程Apollo,需要使用Apollo来配合SpringCloud Gateway实现动态路由功能。

相关资料:

使用Nacos实现Spring Cloud Gateway的动态路由
官方提供的apollo实现zuul网关的动态路由

代码:

依赖:

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-gateway</artifactId>

</dependency>

<dependency>

    <groupId>com.ctrip.framework.apollo</groupId>

    <artifactId>apollo-client</artifactId>

    <version>1.1.2</version>

</dependency>

gateway路由CRUD:

@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 Mono<ResponseEntity<Object>> delete(String id) {

        return this.routeDefinitionWriter.delete(Mono.just(id))

                .then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build())))

                .onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build()));

    }


    @Override

    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {

        this.publisher = applicationEventPublisher;

    }

}

路由刷新监听:

@Slf4j

@Component

public class GatewayPropertiesRefresher implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    private final GatewayProperties gatewayProperties;

    private final DynamicRouteServiceImpl dynamicRouteService;


    public GatewayPropertiesRefresher(DynamicRouteServiceImpl dynamicRouteService, GatewayProperties gatewayProperties) {

        this.dynamicRouteService = dynamicRouteService;

        this.gatewayProperties = gatewayProperties;

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        this.applicationContext = applicationContext;

    }


    /**

      apollo配置监听器,默认监听的是application命名空间

      @param changeEvent

     */
    @ApolloConfigChangeListener({"gateway-routes"})

    public void onChange(ConfigChangeEvent changeEvent) {


        boolean gatewayPropertiesChanged = false;


        for (String changedKey : changeEvent.changedKeys()) {


            //前缀为spring.cloud.gateway的key发生了改变(gateway的配置发生了改变)

            if (changedKey.startsWith("spring.cloud.gateway.")) {

                gatewayPropertiesChanged = true;

                break;

            }

        }

        //更新gateway配置

        if (gatewayPropertiesChanged) {

            refreshGatewayProperties(changeEvent);

        }

    }


    /**

      更新SpringApplicationContext对象,并更新路由

      @param changeEvent

     */

    private void refreshGatewayProperties(ConfigChangeEvent changeEvent) {


        log.info("Refreshing Gateway properties!");

        //更新配置

        this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));

        //更新路由
    gatewayProperties.getRoutes().forEach(dynamicRouteService::update);

        log.info("Gateway properties refreshed!");

    }


}

测试效果:

在apollo配置中心修改路由配置,访问自己设置的对应的网址就好啦(不太明白的建议具体看一看本文开头的两篇文章)~