一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - SpringCloud Zuul在何種情況下使用Hystrix及問題小結

SpringCloud Zuul在何種情況下使用Hystrix及問題小結

2021-06-15 10:15Trust_FreeDom Java教程

這篇文章主要介紹了SpringCloud Zuul在何種情況下使用Hystrix 及問題小結,感興趣的朋友跟隨小編一起看看吧

首先,引入spring-cloud-starter-zuul之后會間接引入:

SpringCloud Zuul在何種情況下使用Hystrix及問題小結

hystrix依賴已經引入,那么何種情況下使用hystrix呢?

在zuul的自動配置類zuulserverautoconfiguration和zuulproxyautoconfiguration中總共會向spring容器注入3個zuul的routefilter,分別是

•simplehostroutingfilter

簡單路由,通過httpclient向預定的url發送請求

生效條件:

requestcontext.getcurrentcontext().getroutehost() != null
 ? && requestcontext.getcurrentcontext().sendzuulresponse()

1、requestcontext中的routehost不為空,routehost就是url,即使用url直連

2、requestcontext中的sendzuulresponse為true,即是否將response發送給客戶端,默認為true

•ribbonroutingfilter

使用ribbon、hystrix和可插入的http客戶端發送請求

生效條件:

(requestcontext.getroutehost() == null && requestcontext.get(service_id_key) != null
 ? && requestcontext.sendzuulresponse())

1、requestcontext中的routehost為空,即url為空

2、requestcontext中的serviceid不為空

3、requestcontext中的sendzuulresponse為true,即是否將response發送給客戶端,默認為true

•sendforwardfilter

forward到本地url

生效條件:

requestcontext.containskey(forward_to_key)
 ? && !requestcontext.getboolean(send_forward_filter_ran, false)

1、requestcontext中包含forward_to_key,即url使用 forward: 映射

2、requestcontext中send_forward_filter_ran為false,send_forward_filter_ran意為“send forward是否運行過了”,在sendforwardfilter#run()時會ctx.set(send_forward_filter_ran, true)

綜上所述,在使用serviceid映射的方法路由轉發的時候,會使用ribbon+hystrix

而哪種路由配置方式是“url映射”,哪種配置方式又是“serviceid映射”呢?

zuul有一個前置過濾器predecorationfilter用于通過routelocator路由定位器決定在何時以何種方式路由轉發

routelocator是用于通過請求地址匹配到route路由的,之后predecorationfilter再通過route信息設置requestcontext上下文,決定后續使用哪個routefilter做路由轉發

所以就引出以下問題:

•什么是route
•routelocator路由定位器如何根據請求路徑匹配路由
•匹配到路由后,predecorationfilter如何設置requestcontext請求上下文

什么是route

我總共見到兩個和route相關的類

zuulproperties.zuulroute,用于和zuul配置文件關聯,保存相關信息

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
org.springframework.cloud.netflix.zuul.filters.route, routelocator找到的路由信息就是這個類,用于路由轉發
public static class zuulroute {
 private string id; //zuulroute的id
 private string path; //路由的pattern,如 /foo/**
 private string serviceid; //要映射到此路由的服務id
 private string url; //要映射到路由的完整物理url
 private boolean stripprefix = true; //用于確定在轉發之前是否應剝離此路由前綴的標志位
 private boolean retryable; //此路由是否可以重試,通常重試需要serviceid和ribbon
 private set<string> sensitiveheaders = new linkedhashset(); //不會傳遞給下游請求的敏感標頭列表
 private boolean customsensitiveheaders = false; //是否自定義了敏感頭列表
}
public class route {
 private string id;
 private string fullpath;
 private string path;
 private string location; //可能是 url 或 serviceid
 private string prefix;
 private boolean retryable;
 private set<string> sensitiveheaders = new linkedhashset<>();
 private boolean customsensitiveheaders;
}

可以看到org.springframework.cloud.netflix.zuul.filters.route和zuulproperties.zuulroute基本一致,只是route用于路由轉發定位的屬性location根據不同的情況,可能是一個具體的url,可能是一個serviceid

routelocator路由定位器如何根據請求路徑匹配路由

zuul在自動配置加載時注入了2個routelocator

•compositeroutelocator: 組合的routelocator,在getmatchingroute()時會依次調用其它的routelocator,先找到先返回;compositeroutelocator的routelocators集合中只有discoveryclientroutelocator
•discoveryclientroutelocator: 可以將靜態的、已配置的路由與來自discoveryclient服務發現的路由組合在一起,來自discoveryclient的路由優先;simpleroutelocator的子類(simpleroutelocator 基于加載到zuulproperties中的配置定位route路由信息)

其中compositeroutelocator是 @primary 的,它是組合多個routelocator的locator,其getmatchingroute()方法會分別調用其它所有routelocator的getmatchingroute()方法,通過請求路徑匹配路由信息,只要匹配到了就馬上返回

默認compositeroutelocator混合路由定位器的routelocators只有一個discoveryclientroutelocator,故只需分析discoveryclientroutelocator#getmatchingroute(path)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//----------discoveryclientroutelocator是simpleroutelocator子類,其實是調用的simpleroutelocator##getmatchingroute(path)
@override
public route getmatchingroute(final string path) {
 return getsimplematchingroute(path);
}
protected route getsimplematchingroute(final string path) {
 if (log.isdebugenabled()) {
  log.debug("finding route for path: " + path);
 }
 // routes是保存路由信息的map,如果此時還未加載,調用locateroutes()
 if (this.routes.get() == null) {
  this.routes.set(locateroutes());
 }
 if (log.isdebugenabled()) {
  log.debug("servletpath=" + this.dispatcherservletpath);
  log.debug("zuulservletpath=" + this.zuulservletpath);
  log.debug("requestutils.isdispatcherservletrequest()="
    + requestutils.isdispatcherservletrequest());
  log.debug("requestutils.iszuulservletrequest()="
    + requestutils.iszuulservletrequest());
 }
 /**
  * 下面的方法主要是先對path做微調
  * 再根據path到routes中匹配到zuulroute
  * 最后根據 zuulroute 和 adjustedpath 生成 route
  */
 string adjustedpath = adjustpath(path);
 zuulroute route = getzuulroute(adjustedpath);
 return getroute(route, adjustedpath);
}

下面我們來看看locateroutes()是如何加載靜態的、已配置的路由與來自discoveryclient服務發現的路由的

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//----------discoveryclientroutelocator#locateroutes() 服務發現路由定位器的locateroutes()
@override
protected linkedhashmap<string, zuulroute> locateroutes() {
 //保存zuulroute的linkedhashmap
 linkedhashmap<string, zuulroute> routesmap = new linkedhashmap<string, zuulroute>();
 //調用父類simpleroutelocator#locateroutes()
 //加載zuulproperties中的所有配置文件中的路由信息
 routesmap.putall(super.locateroutes());
 //如果服務發現客戶端discovery存在
 if (this.discovery != null) {
  //將routesmap已經存在的配置文件中的zuulroute放入staticservices<serviceid, zuulroute>
  map<string, zuulroute> staticservices = new linkedhashmap<string, zuulroute>();
  for (zuulroute route : routesmap.values()) {
   string serviceid = route.getserviceid();
   //如果serviceid為null,以id作為serviceid,此情況適合 zuul.routes.xxxx=/xxxx/** 的情況
   if (serviceid == null) {
    serviceid = route.getid();
   }
   if (serviceid != null) {
    staticservices.put(serviceid, route);
   }
  }
  // add routes for discovery services by default
  list<string> services = this.discovery.getservices(); //到注冊中心找到所有service
  string[] ignored = this.properties.getignoredservices()
    .toarray(new string[0]);
  //遍歷services
  for (string serviceid : services) {
   // ignore specifically ignored services and those that were manually
   // configured
   string key = "/" + maproutetoservice(serviceid) + "/**";
   //如果注冊中心的serviceid在staticservices集合中,并且此路由沒有配置url
   //那么,更新路由的location為serviceid
   if (staticservices.containskey(serviceid)
     && staticservices.get(serviceid).geturl() == null) {
    // explicitly configured with no url, cannot be ignored
    // all static routes are already in routesmap
    // update location using serviceid if location is null
    zuulroute staticroute = staticservices.get(serviceid);
    if (!stringutils.hastext(staticroute.getlocation())) {
     staticroute.setlocation(serviceid);
    }
   }
   //如果注冊中心的serviceid不在忽略范圍內,且routesmap中還沒有包含,添加到routesmap
   if (!patternmatchutils.simplematch(ignored, serviceid)
     && !routesmap.containskey(key)) {
    // not ignored
    routesmap.put(key, new zuulroute(key, serviceid));
   }
  }
 }
 // 如果routesmap中有 /** 的默認路由配置
 if (routesmap.get(default_route) != null) {
  zuulroute defaultroute = routesmap.get(default_route);
  // move the defaultserviceid to the end
  routesmap.remove(default_route);
  routesmap.put(default_route, defaultroute);
 }
 //將routesmap中的數據微調后,放到values<string, zuulroute>,返回
 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;
}

此方法運行后就已經加載了配置文件中所有路由信息,以及注冊中心中的服務路由信息,有的通過url路由,有的通過serviceid路由

只需根據本次請求的requesturi與 路由的pattern匹配找到對應的路由

匹配到路由后,predecorationfilter如何設置requestcontext請求上下文

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//----------predecorationfilter前置過濾器
@override
public object run() {
 requestcontext ctx = requestcontext.getcurrentcontext();
 final string requesturi = this.urlpathhelper.getpathwithinapplication(ctx.getrequest());
 route route = this.routelocator.getmatchingroute(requesturi); //找到匹配的路由
 //----------------到上面為止是已經分析過的,根據requesturi找到匹配的route信息
 // ==== 匹配到路由信息
 if (route != null) {
  string location = route.getlocation();
  if (location != null) {
   ctx.put(request_uri_key, route.getpath());//requestcontext設置 requesturi:路由的pattern路徑
   ctx.put(proxy_key, route.getid());//requestcontext設置 proxy:路由id
   //設置需要忽略的敏感頭信息,要么用全局默認的,要么用路由自定義的
   if (!route.iscustomsensitiveheaders()) {
    this.proxyrequesthelper
      .addignoredheaders(this.properties.getsensitiveheaders().toarray(new string[0]));
   }
   else {
    this.proxyrequesthelper.addignoredheaders(route.getsensitiveheaders().toarray(new string[0]));
   }
   //設置重試信息
   if (route.getretryable() != null) {
    ctx.put(retryable_key, route.getretryable());
   }
   //如果location是 http/https開頭的,requestcontext設置 routehost:url
   //如果location是 forward:開頭的,requestcontext設置 forward信息、routehost:null
   //其它 requestcontext設置 serviceid、routehost:null、x-zuul-serviceid
   if (location.startswith(http_scheme+":") || location.startswith(https_scheme+":")) {
    ctx.setroutehost(geturl(location));
    ctx.addoriginresponseheader(service_header, location);
   }
   else if (location.startswith(forward_location_prefix)) {
    ctx.set(forward_to_key,
      stringutils.cleanpath(location.substring(forward_location_prefix.length()) + route.getpath()));
    ctx.setroutehost(null);
    return null;
   }
   else {
    // set serviceid for use in filters.route.ribbonrequest
    ctx.set(service_id_key, location);
    ctx.setroutehost(null);
    ctx.addoriginresponseheader(service_id_header, location);
   }
   //是否添加代理頭信息 x-forwarded-for
   if (this.properties.isaddproxyheaders()) {
    addproxyheaders(ctx, route);
    string xforwardedfor = ctx.getrequest().getheader(x_forwarded_for_header);
    string remoteaddr = ctx.getrequest().getremoteaddr();
    if (xforwardedfor == null) {
     xforwardedfor = remoteaddr;
    }
    else if (!xforwardedfor.contains(remoteaddr)) { // prevent duplicates
     xforwardedfor += ", " + remoteaddr;
    }
    ctx.addzuulrequestheader(x_forwarded_for_header, xforwardedfor);
   }
   //是否添加host頭信息
   if (this.properties.isaddhostheader()) {
    ctx.addzuulrequestheader(httpheaders.host, tohostheader(ctx.getrequest()));
   }
  }
 }
 // ==== 沒有匹配到路由信息
 else {
  log.warn("no route found for uri: " + requesturi);
  string fallbackuri = requesturi;
  string fallbackprefix = this.dispatcherservletpath; // default fallback
               // servlet is
               // dispatcherservlet
  if (requestutils.iszuulservletrequest()) {
   // remove the zuul servletpath from the requesturi
   log.debug("zuulservletpath=" + this.properties.getservletpath());
   fallbackuri = fallbackuri.replacefirst(this.properties.getservletpath(), "");
   log.debug("replaced zuul servlet path:" + fallbackuri);
  }
  else {
   // remove the dispatcherservlet servletpath from the requesturi
   log.debug("dispatcherservletpath=" + this.dispatcherservletpath);
   fallbackuri = fallbackuri.replacefirst(this.dispatcherservletpath, "");
   log.debug("replaced dispatcherservlet servlet path:" + fallbackuri);
  }
  if (!fallbackuri.startswith("/")) {
   fallbackuri = "/" + fallbackuri;
  }
  string forwarduri = fallbackprefix + fallbackuri;
  forwarduri = forwarduri.replaceall("//", "/");
  ctx.set(forward_to_key, forwarduri);
 }
 return null;
}

總結:

•只要引入了spring-cloud-starter-zuul就會間接引入ribbon、hystrix
•路由信息可能是從配置文件中加載的,也可能是通過discoveryclient從注冊中心加載的
•zuul是通過前置過濾器predecorationfilter找到與當前requesturi匹配的路由信息,并在requestcontext中設置相關屬性的,后續的route filter會根據requestcontext中的這些屬性判斷如何路由轉發
•route filter主要使用 simplehostroutingfilter 和 ribbonroutingfilter
•當requestcontext請求上下文中存在routehost,即url直連信息時,使用simplehostroutingfilter簡單host路由
•當requestcontext請求上下文中存在serviceid,即服務id時(可能會與注冊中心關聯獲取服務列表,或者讀取配置文件中serviceid.ribbon.listofservers的服務列表),使用ribbonroutingfilter,會使用ribbon、hystrix

總結

以上所述是小編給大家介紹的springcloud zuul在何種情況下使用hystrix,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:https://www.cnblogs.com/trust-freedom/p/9982680.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品亚洲午夜一区二区三区 | 果冻传媒在线播放观看228集 | 免费看视频高清在线观看 | chinese男性厕所撒尿合集 | 厨房里摸着乳丰满在线观看 | 秋霞理论最新三级理论最 | 91久久色| 秋霞理论在一l级毛片 | 久久黄色录像 | 成人在线一区二区 | 人皮高跟鞋在线观看 | 国产精品久久一区 | 日本高清在线播放 | 国产福利一区二区精品视频 | 亚洲人影院| 无码专区aaaaaa免费视频 | 美女福利视频午夜在线 | 星星动漫无删减在线观看 | 亚洲国产成人久久99精品 | 爽爽影院免费观看 | 91次元成年破解版 | 国产第一页在线视频 | 成年视频在线播放 | 四缺一小说 | 久久国产乱子伦精品免费不卡 | 精东影业传媒全部作品 | 亚洲成人视屏 | 免费看日产一区二区三区 | 明星ai智能人脸替换造梦在线播放 | 国内外成人在线视频 | 青柠影院在线观看免费完整版1 | 99成人国产精品视频 | 变态 调教 视频 国产九色 | 国产清纯白嫩大学生正在播放 | 欧美专区视频 | 午夜国产精品视频 | 脱女学小内内摸出水网站免费 | 国产成人福利美女观看视频 | 欧美一卡2卡3卡四卡海外精品 | 成人在线视频国产 | 莫莉瑞典1977k |