Spring Cloud Zuul設置動態路由規則

最近項目中有一個需求:由於有多個服務需要接入系統,並且後續會越來越多服務接入,此時外部系統調用這些服務會比較麻煩,不同的端口,不同的路徑,並且權限不好管理。此時就想到了將對這些服務的請求統一通過網關轉發,統一生成一個路由前綴,並且轉發前統一在網關進行鑑權。當這些服務註冊到eureka時,動態的生成服務的路由規則,避免在配置文件中手動配置。

創建一個類繼承SimpleRouteLocator,實現RefreshableRouteLocator接口:

import com.netflix.appinfo.InstanceInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient;
import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 自定義適配器服務路由規則
 *
 * @author hsz
 */

@Slf4j
public class AdapterRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

    @Autowired
    private DiscoveryClient discoveryClient;

    public AdapterRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
    }

    @Override
    public void refresh() {
        doRefresh();
    }

    @Override
    protected Map<String, ZuulRoute> locateRoutes() {
        //重新定義一個路由映射map
        LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
        //獲取所有服務
        List<String> services = discoveryClient.getServices();
        //設置適配器路由規則
        for (String service : services) {
            List<ServiceInstance> serviceInstances = discoveryClient.getInstances(service);
            serviceInstances.forEach(serviceInstance -> {
                EurekaDiscoveryClient.EurekaServiceInstance instance = (EurekaDiscoveryClient.EurekaServiceInstance) serviceInstance;
                InstanceInfo instanceInfo = instance.getInstanceInfo();
                if ("ADAPTER-SERVICE".equals(instanceInfo.getAppGroupName())) {
                    ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
                    zuulRoute.setId(instanceInfo.getAppName().toLowerCase());
                    zuulRoute.setUrl(serviceInstance.getUri().toString());
                    zuulRoute.setRetryable(false);
                    String path = "/adapter/" + instanceInfo.getAppName().toLowerCase() + "/**";
                    zuulRoute.setPath(path);
                    routesMap.put(path, zuulRoute);
                }
            });
        }
        return routesMap;
    }
}

主要的邏輯都在locateRoutes()方法中。首先定義一個路由映射map,用來存放路由規則。通過DiscoveryClient獲取到服務註冊列表,將組名爲“ADAPTER-SERVICE”的適配器服務過濾出來解析並構造路由放入到map中,最後這個routesMap就是自定義的路由規則。

Zuul在自動配置加載時會默認注入了2個自帶RouteLocator:
CompositeRouteLocator:包含了其他所有的RouteLocator,匹配路徑時也是通過這個類的getMatchingRoute方法依次調用其他RouteLocator的getMatchingRoute方法類匹配,只要匹配到第一個就返回,不會再往下匹配;
DiscoveryClientRouteLocator:這個路由器包括兩部分規則,一個是加載的父類SimpleRouteLocator中的規則,即配置文件中的路由配置;一個是根據服務註冊列表生成的,匹配路徑是“/服務名/**”,如果配置了ignored-services: ‘*’,則不會生成這個規則。並且如果有匹配路徑是“/**”的,則將它移到最後面。

PreDecorationFilter前置過濾器通過CompositeRouteLocator來獲取匹配的路由。

最後用配置類使這個路由規則生效

import com.fdjw.msgateway.route.AdapterRouteLocator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author hsz
 */

@Configuration
public class RouteConfig {

    private final ZuulProperties zuulProperties;
    private final ServerProperties server;

    @Autowired
    public RouteConfig(ZuulProperties zuulProperties, ServerProperties server) {
        this.zuulProperties = zuulProperties;
        this.server = server;
    }

    @Bean
    public AdapterRouteLocator getRouteLocator() {
        return new AdapterRouteLocator(server.getServlet().getContextPath(), zuulProperties);
    }
}

springboot版本:2.1.3

參考鏈接:
https://www.cnblogs.com/trust-freedom/p/9982680.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章