springcloud(第九篇)netflix zuul
netflix zuul
introduction
zuul
用來提供動態路由、監控、授權、安全、排程等等的邊緣服務(edge service)
ZuulFilter
ZuulFilter
是Zuul
中核心元件,通過繼承該抽象類,覆寫幾個關鍵方法達到自定義排程請求的作用,這裡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執行順序,通過數字指定
shouldFilter
:filter是否需要執行true
執行false
不執行
run
: filter具體邏輯
filterType
:filter型別,分為以下幾種
pre
:請求執行之前filter
route
: 處理請求,進行路由
post
: 請求處理完成後執行的filter
error
:出現錯誤時執行的filter
quick start
直接給出一個簡單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.
*/
@SpringBootApplication
public 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;
}
}
servlet註冊
通過ServletRegistrationBean
構造ZuulServlet
,該Servlet用以進行filter
執行排程以及監控等等操作
訪問 http://localhost:8080/test 進入該servlet
filter註冊
通過FilterRegistrationBean
進行filter註冊,ContextLifecycleFilter
的核心功能是為了清除RequestContext
;
請求上下文通過ThreadLocal
儲存,因此需要在請求完成後刪除該物件。
CommandLineRunner
CommandLineRunner
介面很簡單,知道spring boot
的知道其功能,在工程啟動後會執行對應run
方法:
MonitoringHelper.initMocks();
啟動監控,這個再後續文章中具體再說
initJavaFilters()
方法中註冊三種類型filter
RequestContext
RequestContext
在zuul
有很重作用,在不同元件傳遞資料都是通過它來實現的
zuul執行流程
借用官網的一張圖片
通過圖片可以清晰看出執行過程,在微服務中後端各種引用,利用zuul進行合理呼叫還是很有必要的,例如 負載、限流、監控、安全等等功能。
zuul with groovy
為了動態修改filter,zuul
利用groovy
,它是基於jvm的語言,語法簡單而且和java很類似,可以簡單的理解為在java語法上進行拓展,但groovy是可以動態載入的,應用釋出到線上後可以在不重啟情況下對業務邏輯進行修改。
為了簡單起見,下面建立一個groovy filter
import com.netflix.zuul.ZuulFilter
import com.netflix.zuul.context.RequestContext
import javax.servlet.http.HttpServletRequest
class 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
}
}
建立一個pre
型別的filter,在run
方法中獲取HttpServletRequest
然後答應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檔案通過絕對路徑指定,如果是實際開發中,可以通過db去儲存groovy檔案。
啟動應用後再訪問該工程,可以發現header資訊全部答應出來。
歡迎關注,您的肯定是對我最大的支援