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方法。這裏主要是獲取兩個地方的配置,一個是咱們的配置文件,一個是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/**
讀取本地的時候,直接從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() + "/**"; } } }
咱們知道了何時觸發路由的從新加載,那咱們能夠在路由信息改變的時候,就調用觸發他的條件,好比RoutesRefreshedEvent。
咱們知道了他的加載流程,先本地再註冊中心,咱們也能夠自定義本身的加載流程,好比先本地,再數據庫,數據庫變動,就觸發RoutesRefreshedEvent時間,達到動態路由的目的。blog