CloudRouteResourceLoader.java 4.67 KB
package com.diligrp.xtrade.gateway.route.impl;

import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.diligrp.xtrade.gateway.config.GatewayResourceLoaderConfiguration;
import com.diligrp.xtrade.gateway.exception.GatewayServiceException;
import com.diligrp.xtrade.gateway.route.DynamicRouteLoaderIntf;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.config.GatewayProperties;
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.ApplicationContext;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @Auther: miaoguoxin
 * @Date: 2020/4/2 14:02
 * @Description: 从云端配置中心加载
 * {@link GatewayResourceLoaderConfiguration} 配置
 */
@Slf4j
public class CloudRouteResourceLoader implements DynamicRouteLoaderIntf {
    /**标记当前gatewayproties的hash值,用于判断配置是否更新过*/
    private static int gatewayPropertiesHash;
    /**防止重复初始化的标记*/
    private static final AtomicBoolean HAS_INIT = new AtomicBoolean(false);

    private final static String GROUP = "DEFAULT_GROUP";
    private final static String ROUTE_CONFIG_NAME = "route.properties";


    @Value("${spring.application.name}")
    private String applicationName;
    @Value("${spring.profiles.active}")
    private String activeProfile;
    @Value("${spring.cloud.nacos.config.file-extension}")
    private String fileType;
    @Autowired
    private ApplicationContext applicationContext;
    @Resource
    private RouteDefinitionWriter routeDefinitionWriter;
    @Autowired
    private ConfigService configService;
    @Autowired
    private GatewayProperties gatewayProperties;

    @Override
    public void init() {
        if (HAS_INIT.compareAndSet(false, true)) {
            this.loadRoutes();
            //用来判断routes是否改变过,避免无效刷新
            gatewayPropertiesHash = gatewayProperties.getRoutes().hashCode();
        }
    }

    @Override
    public void refreshApis() {

    }

    @Override
    public void refreshRoutes() {
        this.notifyRefreshRoutes();
    }


    /**
     * 通过nacos配置中心监听配置变化,
     * 完成路由资源装载
     * @author miaoguoxin
     * @date 2020/4/10
     */
    private void loadRoutes() {
        //只有放到标准的配置文件下,才能够成功刷新配置
        String configFile = String.format("%s-%s.%s", applicationName, activeProfile, fileType);
        try {
            configService.getConfigAndSignListener(
                    ROUTE_CONFIG_NAME,
                    GROUP,
                    5000,
                    new Listener() {
                        @Override
                        public void receiveConfigInfo(String configInfo) {
                            Timer timer = new Timer(true);
                            TimerTask task = new TimerTask() {
                                @Override
                                public void run() {
                                    notifyRefreshRoutes();
                                }
                            };
                            //由于属性刷新有延迟,这里延长点时间
                            timer.schedule(task, 5000);
                        }

                        @Override
                        public Executor getExecutor() {
                            return null;
                        }
                    });
        } catch (NacosException e) {
            throw new GatewayServiceException("load route resource failed", e);
        }
    }


    private void notifyRefreshRoutes() {
        synchronized (CloudRouteResourceLoader.this){
            if (gatewayPropertiesHash == gatewayProperties.getRoutes().hashCode()) {
                return;
            }
            List<RouteDefinition> routes = gatewayProperties.getRoutes();
            routes.forEach(definition ->
                    routeDefinitionWriter.save(Mono.just(definition)).subscribe());
            applicationContext.publishEvent(new RefreshRoutesEvent(this));
            gatewayPropertiesHash = gatewayProperties.getRoutes().hashCode();
            log.info("refresh route success");
        }
    }

}