Spring Cloud Zuul原始碼分析
如何使用Spring Cloud Zuul?
之前的文章中,我們學習了Spring Cloud Zuul如何使用,這裡再回顧下:
1.引入依賴,在啟動類中新增@EnableZuulProxy,宣告這是一個Zuul代理。
2.註冊到Eureka Server,啟動服務,訪問這個埠,url中帶上要請求的服務名。
Spring Cloud Zuul原始碼分析
既然是添加了@EnableZuulProxy註解,那還是先進入這個註解找線索吧。
/**
* Sets up a Zuul server endpoint and installs some reverse proxy filters in it, so it can
* forward requests to backend servers. The backends can be registered manually through
* configuration or via DiscoveryClient.
*
* @see EnableZuulServer for how to get a Zuul server without any proxying
*
* @author Spencer Gibb
* @author Dave Syer
*/
@EnableCircuitBreaker
@EnableDiscoveryClient
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyConfiguration.class)
public @interface EnableZuulProxy {
}
從註釋中可以看到,這個註解會啟動一個Zuul server,並且給這個Zuul server裝配一些代理過濾器,下面還提到了一個@EnableZuulServer註解,這個註解可以開啟一個Zuul server,但是不配置代理。@EnableZuulProxy可以看成是@EnableZuulServer的增強版。
@EnableZuulProxy註解上import了ZuulProxyConfiguration類,從名字上看,這個就是zuul代理的配置類,這個類中,定義了DiscoveryClient和其他一些負載均衡相關的類,還初始化了一些Filter。
ZuulProxyConfiguration類繼承了ZuulConfiguration,這個配置類就是對zuul進行一些配置的,裡面可以看到會初始化ZuulServlet和其他一些Zuul的bean以及Filter。
在ZuulConfiguration中,還有個ZuulFilterConfiguration內部類,這個內部類中會初始化ZuulFilterInitializer,存放所有的Filters。
Zuul定義了四種類型的過濾器:
1.Pre Filter
2.Route Filter
3.Post Filter
4.Error Filter
Pre過濾器是請求路由到具體的服務之前執行的,可以用來做安全驗證,引數驗證等操作。
Route過濾器是用來將請求路由到具體的服務上。
Post過濾器是請求已經被路由到微服務之後執行的。
如果Pre,Route和Post過濾器在執行過程中發生了異常,會由Error過濾器處理。
下面是這四種過濾器的執行順序:
請求會先經過per filters,然後到routing filters,再去請求到具體的服務上,返回response之後,就經過post filters。如果發生異常,交給error filters。還可以自己自己定義filters。
自己定義filter,需要繼承ZuulFilter抽象類,重寫下面這四個方法:
public class MyFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return false;
}
@Override
public Object run() {
return null;
}
}
其中,filterType方法,返回這個filter的型別,比如是pre型別的過濾器。
filterOrder是定義這個過濾器的執行順序,值越小,越先執行。
shouldFIlter返回該過濾器是否開啟,返回false,表示不執行這個過濾器。
run就是具體過濾器中需要執行的方法。
接下來再看下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();
}
}
從ZuulServlet中,也可以看出這個執行的邏輯。Zuul的主要功能,就是在這些Filter中了。