摘要:是開源的微服務(wù)網(wǎng)關(guān),它可以和,等組件配合使用,網(wǎng)上也有很多如何使用的文章,我們也在生產(chǎn)環(huán)境使用了,所以讀了下的源碼,下面把它分享出來,與大家探討下核心原理。
Zuul是Netflix開源的微服務(wù)網(wǎng)關(guān),它可以和Eureka,consul,Ribbon,Hystrix等組件配合使用,網(wǎng)上也有很多如何使用zuul的文章,我們也在生產(chǎn)環(huán)境使用了,所以讀了下zuul的源碼,下面把它分享出來,與大家探討下zuul核心原理。
一、spring-cloud-zuul是如何映射路由的?
zuul的路由映射是使用springMVC功能,我們知道springMVC有兩大核心組件:
HandlerMapping:映射器
HandlerAdapter:適配器
具體的springMVC原理這里不做講解,我們來看下zuul是如何自定義HandlerMapping來注冊路由映射的?下圖是springMVC的類繼承關(guān)系
很清晰看到Zuul提供的ZuulHandlerMapping是AbstractUrlHandlerMapping的子類,這個(gè)類是根據(jù)url來查找處理器,核心處理方法在lookupHandler里面:
@Override protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { if (this.errorController != null && urlPath.equals(this.errorController.getErrorPath())) { return null; } //過濾忽略的路由規(guī)則 String[] ignored = this.routeLocator.getIgnoredPaths().toArray(new String[0]); if (PatternMatchUtils.simpleMatch(ignored, urlPath)) { return null; } RequestContext ctx = RequestContext.getCurrentContext(); if (ctx.containsKey("forward.to")) { return null; } if (this.dirty) { synchronized (this) { if (this.dirty) {//如果沒有加載過路由或者路由有刷新,則加載路由 registerHandlers(); this.dirty = false; } } } //根據(jù)url調(diào)用父類獲取處理器 return super.lookupHandler(urlPath, request); } private void registerHandlers() { //使用路由定位器獲取路由規(guī)則 Collectionroutes = this.routeLocator.getRoutes(); if (routes.isEmpty()) { this.logger.warn("No routes found from RouteLocator"); } else { for (Route route : routes) { //調(diào)用父類,注冊處理器 registerHandler(route.getFullPath(), this.zuul); } } }
梳理一下,以上方法的核心幾步:
判斷urlPath是否被忽略,如果忽略則返回null
判斷路由規(guī)則有沒有加載過或者更新過,沒有加載或者有更新則重新加載
注冊處理器的時(shí)候,使用的是ZuulController,是Controller的子類,對應(yīng)的適配器是SimpleControllerHandlerAdapter,也就說每一個(gè)路由規(guī)則公共處理器都是ZuulController,這個(gè)處理器最終會調(diào)用ZuulServlet經(jīng)過zuul定義的和自定義的攔截器,這個(gè)zuul的核心,后面我們作詳細(xì)講解。
根據(jù)url找到處理器,返回
二、路由定位器
在上面我們注冊了路由規(guī)則,而路由規(guī)則是由路由定位器獲取,那么zuul給我們提供哪些路由定位器,類圖如下:
SimpleRouteLocator:主要加載配置文件的路由規(guī)則
DiscoveryClientRouteLocator:服務(wù)發(fā)現(xiàn)的路由定位器,去注冊中心如Eureka,consul等拿到服務(wù)名稱,以這樣的方式/服務(wù)名稱/**映射成路由規(guī)則
CompositeRouteLocator:復(fù)合路由定位器,主要集成所有的路由定位器(如配置文件路由定位器,服務(wù)發(fā)現(xiàn)定位器,自定義路由定位器等)來路由定位。
RefreshableRouteLocator:路由刷新,只有實(shí)現(xiàn)了此接口的路由定位器才能被刷新
擴(kuò)展:
1、這里我們可以實(shí)現(xiàn)自己的路由定位器,擴(kuò)展自己想要的功能,如從數(shù)據(jù)庫加載路由規(guī)則,可以參考文章
2、利用服務(wù)發(fā)現(xiàn)的路由定位器去加載理由規(guī)則的時(shí)候,我們只是簡單的是把serviceId映射成路由規(guī)則,有的時(shí)間我們還是想在serviceId和路由之間提供約定 ,于是我們可以使用PatternServiceRouteMapper來實(shí)現(xiàn)
@Bean public PatternServiceRouteMapper serviceRouteMapper() { return new PatternServiceRouteMapper( "(?^.+)-(? v.+$)", "${version}/${name}"); }
這樣serviceId:myusers-v1將被映射到路由/ v1 / myusers / **,這里任何正則表達(dá)式都可以接受,根據(jù)自己需要自己設(shè)定。
三、過濾器
前面提到,所以路由請求都會被控制器ZuulControoler攔截到,最終交由ZuulServlet來處理,核心處理代碼如下:
@Override public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException { try { init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); // Marks this request as having passed through the "Zuul engine", as opposed to servlets // explicitly bound in web.xml, for which requests will not have the same data attached RequestContext context = RequestContext.getCurrentContext(); context.setZuulEngineRan(); try { preRoute(); } catch (ZuulException e) { error(e); postRoute(); return; } try { route(); } catch (ZuulException e) { error(e); postRoute(); return; } try { postRoute(); } catch (ZuulException e) { error(e); return; } } catch (Throwable e) { error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName())); } finally { RequestContext.getCurrentContext().unset(); } }
這段代碼體現(xiàn)了zuul過濾器的生命周期,官方提供了一張圖很形象的展示:
zuul把過濾器分為四個(gè)階段,分別是
pre:主要是在請求路由之前調(diào)用,很多驗(yàn)證可以在這里做
route:在路由請求時(shí)候被調(diào)用,主要用來轉(zhuǎn)發(fā)請求
post:主要用來處理響應(yīng)請求
error:當(dāng)錯(cuò)誤發(fā)生時(shí),會經(jīng)由這個(gè)類型的過濾器處理
zuul為我們提供了各個(gè)階段的過濾器一共10個(gè)
這里我們來著重看下路由階段的兩個(gè)過濾器
SimpleHostRoutingFilter:主要提供當(dāng)路由設(shè)置url方式時(shí),由這個(gè)路由器來轉(zhuǎn)發(fā)請求,使用的是apache的CloseableHttpClient來發(fā)送http請求
RibbonRoutingFilter:當(dāng)路由設(shè)置serviceId時(shí),由此過濾器來轉(zhuǎn)發(fā)請求,這里集成了ribbon,Hystrix,實(shí)現(xiàn)負(fù)載均衡,熔斷的功能;默認(rèn)情況下也是使用apache的HttpClient來轉(zhuǎn)發(fā)請求
未完待續(xù)......
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/76653.html
摘要:不過在出來之后支持異步了,可以把業(yè)務(wù)操作放到獨(dú)立的線程池里面去,這樣可以盡快釋放線程,本身也支持異步了,本篇文章將帶你如何使用的異步特性來改造優(yōu)化其性能。 ? 我們知道spring-cloud-zuul是依賴springMVC來注冊路由的,而springMVC又是在建立在servlet之上的(這里微服務(wù)專家楊波老師寫過一篇文章講述其網(wǎng)絡(luò)模型,可以參考看看),在servlet3.0...
摘要:前言在體系中扮演著統(tǒng)一網(wǎng)關(guān)的角色,負(fù)責(zé)與外部交互。與結(jié)合使用,可以根據(jù)服務(wù)名來訪問后端的服務(wù),對于而言,也是一個(gè)。這段代碼表示,如果請求中沒有信息,就會報(bào)錯(cuò)。 前言 Zuul在Spring Cloud 體系中扮演著統(tǒng)一網(wǎng)關(guān)的角色,負(fù)責(zé)與外部交互。用戶可以通過不同的URL特征來訪問不同的后端服務(wù),類似于Nginx代理的效果。Zuul與Eureka結(jié)合使用,可以根據(jù)服務(wù)名來訪問后端的服務(wù),...
摘要:事實(shí)是只是部分語言的不同表示法。基于這些,解析器會進(jìn)行立即或者懶解析。然而,解析器做了完全不相關(guān)的額外無用功即解析函數(shù)。這里不解析函數(shù),該函數(shù)聲明了卻沒有指出其用途。所以之前的例子,解析器實(shí)際上 原文請查閱這里,本文采用知識共享署名 4.0 國際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第十四章。 概...
摘要:事實(shí)是只是部分語言的不同表示法。基于這些,解析器會進(jìn)行立即或者懶解析。然而,解析器做了完全不相關(guān)的額外無用功即解析函數(shù)。這里不解析函數(shù),該函數(shù)聲明了卻沒有指出其用途。所以之前的例子,解析器實(shí)際上 原文請查閱這里,本文采用知識共享署名 4.0 國際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第十四章。 概...
閱讀 3779·2021-11-25 09:43
閱讀 2199·2021-11-23 10:13
閱讀 831·2021-11-16 11:44
閱讀 2379·2019-08-29 17:24
閱讀 1391·2019-08-29 17:17
閱讀 3486·2019-08-29 11:30
閱讀 2590·2019-08-26 13:23
閱讀 2350·2019-08-26 12:10