zuul
用來提供動(dòng)態(tài)路由、監(jiān)控、授權(quán)、安全、調(diào)度等等的邊緣服務(wù)(edge service)
ZuulFilter
是Zuul
中核心組件,通過繼承該抽象類,覆寫幾個(gè)關(guān)鍵方法達(dá)到自定義調(diào)度請(qǐng)求的作用,這里filter不是Java web
中的filter,不要混淆.
new ZuulFilter() { @Override public int filterOrder() { return 0; } @Override public String filterType() { return null; } @Override public boolean shouldFilter() { return false; } @Override public Object run() { return null; } }
filterOrder
:filter執(zhí)行順序,通過數(shù)字指定
shouldFilter
:filter是否需要執(zhí)行true
執(zhí)行false
不執(zhí)行
run
: filter具體邏輯
filterType
:filter類型,分為以下幾種
pre
:請(qǐng)求執(zhí)行之前filter
route
: 處理請(qǐng)求,進(jìn)行路由
post
: 請(qǐng)求處理完成后執(zhí)行的filter
error
:出現(xiàn)錯(cuò)誤時(shí)執(zhí)行的filter
直接給出一個(gè)簡(jiǎn)單demo,通過demo代碼再具體解析
package com.lkl.springcloud.zuul;import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.ContextLifecycleFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.filters.FilterRegistry;import com.netflix.zuul.http.ZuulServlet;import com.netflix.zuul.monitoring.MonitoringHelper;import org.springframework.boot.CommandLineRunner;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.builder.SpringApplicationBuilder;import org.springframework.boot.context.embedded.FilterRegistrationBean;import org.springframework.boot.context.embedded.ServletRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.stereotype.Component;import java.io.IOException;/** * Created by liaokailin on 16/5/24. */@SpringBootApplicationpublic class Application { public static void main(String[] args) { new SpringApplicationBuilder(Application.class).web(true).run(args); } @Component public static class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { MonitoringHelper.initMocks(); initJavaFilters(); } private void initJavaFilters() { final FilterRegistry r = FilterRegistry.instance(); r.put("javaPreFilter", new ZuulFilter() { @Override public int filterOrder() { return 50000; } @Override public String filterType() { return "pre"; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { System.out.println("running javaPreFilter"); RequestContext.getCurrentContext().set("name", "liaokailin"); return null; } }); r.put("javaRoutingFilter", new ZuulFilter() { @Override public int filterOrder() { return 50000; } @Override public String filterType() { return "route"; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { System.out.println("running javaRoutingFilter"); try { RequestContext.getCurrentContext().getResponse().sendRedirect("http://blog.csdn.net/liaokailin/"); } catch (IOException e) { e.printStackTrace(); } return null; } }); r.put("javaPostFilter", new ZuulFilter() { @Override public int filterOrder() { return 50000; } @Override public String filterType() { return "post"; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { System.out.println("running javaPostFilter"); System.out.println(RequestContext.getCurrentContext().get("name").toString()); return null; } }); } } @Bean public ServletRegistrationBean zuulServlet() { ServletRegistrationBean servlet = new ServletRegistrationBean(new ZuulServlet()); servlet.addUrlMappings("/test"); return servlet; } @Bean public FilterRegistrationBean contextLifecycleFilter() { FilterRegistrationBean filter = new FilterRegistrationBean(new ContextLifecycleFilter()); filter.addUrlPatterns("/*"); return filter; }}
通過ServletRegistrationBean
構(gòu)造ZuulServlet
,該Servlet用以進(jìn)行filter
執(zhí)行調(diào)度以及監(jiān)控等等操作
訪問 http://localhost:8080/test 進(jìn)入該servlet
通過FilterRegistrationBean
進(jìn)行filter注冊(cè),ContextLifecycleFilter
的核心功能是為了清除RequestContext
;
請(qǐng)求上下文通過ThreadLocal
存儲(chǔ),因此需要在請(qǐng)求完成后刪除該對(duì)象。
CommandLineRunner
接口很簡(jiǎn)單,知道spring boot
的知道其功能,在工程啟動(dòng)后會(huì)執(zhí)行對(duì)應(yīng)run
方法:
MonitoringHelper.initMocks();
啟動(dòng)監(jiān)控,這個(gè)再后續(xù)文章中具體再說 initJavaFilters()
方法中注冊(cè)三種類型filter
RequestContext
在zuul
有很重作用,在不同組件傳遞數(shù)據(jù)都是通過它來實(shí)現(xiàn)的
啟動(dòng)工程后訪問 http://localhost:8080/test 可以看到后臺(tái)答應(yīng)消息,頁(yè)面也會(huì)定位到我的博客首頁(yè)。
借用官網(wǎng)的一張圖片
通過圖片可以清晰看出執(zhí)行過程,在微服務(wù)中后端各種引用,利用zuul進(jìn)行合理調(diào)用還是很有必要的,例如 負(fù)載、限流、監(jiān)控、安全等等功能。
為了動(dòng)態(tài)修改filter,zuul
利用groovy
,它是基于jvm的語言,語法簡(jiǎn)單而且和Java很類似,可以簡(jiǎn)單的理解為在java語法上進(jìn)行拓展,但groovy是可以動(dòng)態(tài)加載的,應(yīng)用發(fā)布到線上后可以在不重啟情況下對(duì)業(yè)務(wù)邏輯進(jìn)行修改。
為了簡(jiǎn)單起見,下面創(chuàng)建一個(gè)groovy filter
import com.netflix.zuul.ZuulFilterimport com.netflix.zuul.context.RequestContextimport javax.servlet.http.HttpServletRequestclass PreRequest extends ZuulFilter{ @Override String filterType() { return "pre" } @Override int filterOrder() { return 1000 } @Override boolean shouldFilter() { return true } @Override Object run() { HttpServletRequest req = RequestContext.currentContext.request as HttpServletRequest Iterator headerIt = req.getHeaderNames().iterator() while (headerIt.hasNext()) { String name = (String) headerIt.next() String value = req.getHeader(name) println("header: " + name + ":" + value) } return null }}
創(chuàng)建一個(gè)pre
類型的filter,在run
方法中獲取HttpServletRequest
然后答應(yīng)header信息
在代碼中加入groovy編譯器,間隔10秒掃描一次groovy文件,其代碼如下:
<dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.4.4</version> </dependency>
FilterLoader.getInstance().setCompiler(new GroovyCompiler()); try { FilterFileManager.setFilenameFilter(new GroovyFileFilter()); FilterFileManager.init(10,"/Users/liaokailin/code/ieda/springcloud/myzuul/src/main/java/com/lkl/springcloud/zuul/filters/groovy/pre"); } catch (Exception e) { throw new RuntimeException(e); }
這里groovy文件通過絕對(duì)路徑指定,如果是實(shí)際開發(fā)中,可以通過db去存儲(chǔ)groovy文件。
啟動(dòng)應(yīng)用后再訪問該工程,可以發(fā)現(xiàn)header信息全部答應(yīng)出來。
ok ~ it’s work ! more about is here
轉(zhuǎn)載請(qǐng)注明
http://blog.csdn.net/liaokailin/article/details/51525908
歡迎關(guān)注,您的肯定是對(duì)我最大的支持
聯(lián)系客服