以前已經集成了網關,而且已經抽離優化成一個服務,如今看他的高級部分。Zuul還有更多的應用場景,好比:鑑權、流量轉發、請求統計等等,這些功能均可以使用Zuul來實現。java
1.鑑權-自定義Filter,進行token檢測。建立一個MyFilterweb
package com.example.zuul.filter; import com.netflix.zuul.ZuulFilter; public class MyFilter extends ZuulFilter { @Override public String filterType() { return "pre"; //定義filter的類型,有pre、route、post、error四種 } @Override public int filterOrder() { return 10; //定義filter的順序,數字越小表示順序越高,越先執行 } @Override public boolean shouldFilter() { return true; //表示是否須要執行該filter,true表示執行,false表示不執行 } @Override public Object run() { return null; //filter須要執行的具體操做 } }
這是一個簡單filter示例,後面咱們進行業務封裝。spring
package com.example.zuul.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; public class TokenFilter extends ZuulFilter { private final Logger logger = LoggerFactory.getLogger(TokenFilter.class); @Override public String filterType() { return "pre"; // 能夠在請求被路由以前調用 } @Override public int filterOrder() { return 0; // filter執行順序,經過數字指定 ,優先級爲0,數字越大,優先級越低 } @Override public boolean shouldFilter() { return true;// 是否執行該過濾器,此處爲true,說明須要過濾 } @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); logger.info("--->>> TokenFilter {},{}", request.getMethod(), request.getRequestURL().toString()); String token = request.getParameter("token");// 獲取請求的參數 if (StringUtils.isNotBlank(token)) { ctx.setSendZuulResponse(true); //對請求進行路由 ctx.setResponseStatusCode(200); ctx.set("isSuccess", true); return null; } else { ctx.setSendZuulResponse(false); //不對其進行路由 ctx.setResponseStatusCode(400); ctx.setResponseBody("token is empty"); ctx.set("isSuccess", false); return null; } } }
仔細對比,發下,二者的區別,就在與run的裏面,進行業務實現部分apache
2.將自創建的filter,加入啓動項裏面api
package com.example.zuul; import com.example.zuul.filter.TokenFilter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.context.annotation.Bean; @SpringBootApplication @EnableZuulProxy //支持網關路由 public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class, args); } /** * 啓動類增長請求攔截 * @return */ @Bean public TokenFilter tokenFilter() { return new TokenFilter(); } }
啓動網關服務,進行檢測app
出現提示,說明自創建的filter已經生效。maven
如今咱們在進行測試路由熔斷,這裏須要說明的是,他與熔斷器的區別,他針對的是一個服務,熔斷器針對的一個遠程調用的方法,進行熔斷處理ide
package com.example.zuul.fallback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @Component public class ProducerFallback implements FallbackProvider{ private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class); //指定要處理的 service。 @Override public String getRoute() { return "spring-cloud-producer"; } public ClientHttpResponse fallbackResponse() { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return 200; } @Override public String getStatusText() throws IOException { return "OK"; } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("The service is unavailable.".getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } @Override public ClientHttpResponse fallbackResponse( String xxx,Throwable cause) { if (cause != null && cause.getCause() != null) { String reason = cause.getCause().getMessage(); logger.info("Excption {}",reason); } return fallbackResponse(); } }
將上面熔斷的服務中止,請求進行嘗試,發現返回spring-boot
The service is unavailable
服務熔斷測試成功post
測試網關的路由重試功能。
1.在zuul網關服務pom中,添加路由重試的依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>zuul</artifactId> <version>0.0.1-SNAPSHOT</version> <name>zuul</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 增長服務註冊中心依賴 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!-- 啓用Zuul Retry-重試功能 --> <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2.配置文件開啓重試的功能
spring.application.name=gateway-service-zuul server.port=8888 #這裏的配置表示,訪問/it/** 直接重定向到http://www.ityouknow.com/** #zuul.routes.baidu.path=/it/** #zuul.routes.baidu.url=http://www.ityouknow.com/ #zuul.routes.hello.path=/api/** #zuul.routes.hello.url=http://localhost:9001/ zuul.routes.api-a.path=/consumer/** zuul.routes.api-a.serviceId=spring-cloud-consumer eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/ #############Zuul Retry############ #是否開啓重試功能 zuul.retryable=true #對當前服務的重試次數 ribbon.MaxAutoRetries=2 #切換相同Server的次數 ribbon.MaxAutoRetriesNextServer=0
3.在相關的方法,增長線程沉睡,觸發屢次重試
package com.example.servicefeign.controller; import com.example.servicefeign.interfaceServer.HelloRemote; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RefreshScope // 使用該註解的類,會在接到SpringCloud配置中心配置刷新的時候,自動將新的配置更新到該類對應的字段中。 @RestController public class HelloController { @Autowired HelloRemote hello;//註冊接口層 @Value("${neo.hello:111}") private String config; @RequestMapping("/hello/{name}") public String index(@PathVariable("name") String name) throws Exception{ System.out.println("調用接口-----------------"); Thread.sleep(1000L); return hello.hello(name); } /** * 獲取配置中心參數 */ @GetMapping("/config") public String getConfig(){ return this.config; } }
index方法中,已經增長了線程休眠時間。
執行程序,進行調用,查看日誌
網關的重試,成功調起