Zuul- 路由加載

Zuul- 啓動,咱們提到了zuulRefreshRoutesListener,能夠用來動態刷新路由,咱們看看他是怎麼加載的。
一下這幾個事件會觸發reset方法。數據庫

public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ContextRefreshedEvent
            || event instanceof RefreshScopeRefreshedEvent
            || event instanceof RoutesRefreshedEvent
            || event instanceof InstanceRegisteredEvent) {
        reset();
    }
    else if (event instanceof ParentHeartbeatEvent) {
        ParentHeartbeatEvent e = (ParentHeartbeatEvent) event;
        resetIfNeeded(e.getValue());
    }
    else if (event instanceof HeartbeatEvent) {
        HeartbeatEvent e = (HeartbeatEvent) event;
        resetIfNeeded(e.getValue());
    }
}

DiscoveryClientRouteLocator#locateRoutes

追着這個方法下去,咱們最後會到DiscoveryClientRouteLocator#locateRoutes方法。這裏主要是獲取兩個地方的配置,一個是咱們的配置文件,一個是Eureka的註冊表信息。segmentfault

protected LinkedHashMap<String, ZuulRoute> locateRoutes() {
    LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
    // 先調用父類的方法,
    routesMap.putAll(super.locateRoutes());
    if (this.discovery != null) {
        Map<String, ZuulRoute> staticServices = new LinkedHashMap<>();
        for (ZuulRoute route : routesMap.values()) {
            String serviceId = route.getServiceId();
            if (serviceId == null) {
                serviceId = route.getId();
            }
            if (serviceId != null) {
                staticServices.put(serviceId, route);
            }
        }
        // 從Eureka獲取註冊表信息
        List<String> services = this.discovery.getServices();
        // 是否有過濾的條件
        String[] ignored = this.properties.getIgnoredServices()
                .toArray(new String[0]);
        for (String serviceId : services) {
            String key = "/" + mapRouteToService(serviceId) + "/**";
            if (staticServices.containsKey(serviceId)
                    && staticServices.get(serviceId).getUrl() == null) {
                ZuulRoute staticRoute = staticServices.get(serviceId);
                if (!StringUtils.hasText(staticRoute.getLocation())) {
                    staticRoute.setLocation(serviceId);
                }
            }
            if (!PatternMatchUtils.simpleMatch(ignored, serviceId)
                    && !routesMap.containsKey(key)) {
                routesMap.put(key, new ZuulRoute(key, serviceId));
            }
        }
    }
    if (routesMap.get(DEFAULT_ROUTE) != null) {
        ZuulRoute defaultRoute = routesMap.get(DEFAULT_ROUTE);
        routesMap.remove(DEFAULT_ROUTE);
        routesMap.put(DEFAULT_ROUTE, defaultRoute);
    }
    // 返回本地配置+Eureka未過濾的註冊表
    LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
    for (Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
        String path = entry.getKey();
        // Prepend with slash if not already present.
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        if (StringUtils.hasText(this.properties.getPrefix())) {
            path = this.properties.getPrefix() + path;
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
        }
        values.put(path, entry.getValue());
    }
    return values;
}

Eureka的註冊表有個IgnoredServices配置,咱們能夠對他進行過濾,這樣避免服務名稱直接暴露出來。this

zuul:
  ignoredServices: '*'
  routes:
    users: /myusers/**

SimpleRouteLocator#locateRoutes

讀取本地的時候,直接從ZuulProperties取值。spa

protected Map<String, ZuulRoute> locateRoutes() {
    LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
    for (ZuulRoute route : this.properties.getRoutes().values()) {
        routesMap.put(route.getPath(), route);
    }
    return routesMap;
}

ZuulProperties被加載的時候,因爲有一個@PostConstruct註解,他會調用init方法。在這裏會根據咱們的配置信息進行賦值serviceId、id、path。code

@PostConstruct
public void init() {
    for (Entry<String, ZuulRoute> entry : this.routes.entrySet()) {
        ZuulRoute value = entry.getValue();
        if (!StringUtils.hasText(value.getLocation())) {
            value.serviceId = entry.getKey();
        }
        if (!StringUtils.hasText(value.getId())) {
            value.id = entry.getKey();
        }
        if (!StringUtils.hasText(value.getPath())) {
            value.path = "/" + entry.getKey() + "/**";
        }
    }
}

流程圖

image

動態路由

咱們知道了何時觸發路由的從新加載,那咱們能夠在路由信息改變的時候,就調用觸發他的條件,好比RoutesRefreshedEvent。
咱們知道了他的加載流程,先本地再註冊中心,咱們也能夠自定義本身的加載流程,好比先本地,再數據庫,數據庫變動,就觸發RoutesRefreshedEvent時間,達到動態路由的目的。blog

相關文章
相關標籤/搜索