在微服務架構中,需要幾個關鍵的組件,服務注冊與發現、服務消費、負載均衡、斷路器、智能路由、配置管理等,由這幾個組件可以組建一個簡單的微服務架構。客戶端的請求首先經過負載均衡(zuul、Ngnix),再到達服務網關(zuul集群),然后再到具體的服務,服務統一注冊到高可用的服務注冊中心集群,服務的所有的配置文件由配置服務管理(下一篇文章講述),配置服務的配置文件放在Git倉庫,方便開發人員隨時改配置。

1. Zuul介紹
Zuul的主要功能是路由和過濾器。路由功能是微服務的一部分,比如/api/user映射到user服務,/api/shop映射到shop服務。zuul實現了負載均衡。以下是微服務結構中,Zuul的基本流程。在接下來的步驟中,我們來創建一個zuul服務, 將/api-feign/**映射到我們之前創建feign-service, 將/api-ribbon/**映射到之前的ribbon-service服務。
2. 創建Zuul的Maven工程,其中關於zuul的依賴是
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency>
完整pom.xml如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 <groupId>cm.chry</groupId> 7 <artifactId>spring.helloworld.zuul.service</artifactId> 8 <version>0.0.1-SNAPSHOT</version> 9 <name>spring.helloworld.zuul.service</name> 10 <description>zuul service demo</description> 11 <parent> 12 <groupId>org.springframework.boot</groupId> 13 <artifactId>spring-boot-starter-parent</artifactId> 14 <version>1.5.3.RELEASE</version> 15 <relativePath/> <!-- lookup parent from repository --> 16 </parent> 17 18 <properties> 19 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 20 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 21 <java.version>1.8</java.version> 22 </properties> 23 24 <dependencies> 25 <dependency> 26 <groupId>org.springframework.cloud</groupId> 27 <artifactId>spring-cloud-starter-eureka</artifactId> 28 </dependency> 29 <dependency> 30 <groupId>org.springframework.boot</groupId> 31 <artifactId>spring-boot-starter-web</artifactId> 32 </dependency> 33 <dependency> 34 <groupId>org.springframework.cloud</groupId> 35 <artifactId>spring-cloud-starter-zuul</artifactId> 36 </dependency> 37 <dependency> 38 <groupId>org.springframework.boot</groupId> 39 <artifactId>spring-boot-starter-test</artifactId> 40 <scope>test</scope> 41 </dependency> 42 </dependencies> 43 44 <dependencyManagement> 45 <dependencies> 46 <dependency> 47 <groupId>org.springframework.cloud</groupId> 48 <artifactId>spring-cloud-dependencies</artifactId> 49 <version>Dalston.RC1</version> 50 <type>pom</type> 51 <scope>import</scope> 52 </dependency> 53 </dependencies> 54 </dependencyManagement> 55 56 <build> 57 <plugins> 58 <plugin> 59 <groupId>org.springframework.boot</groupId> 60 <artifactId>spring-boot-maven-plugin</artifactId> 61 </plugin> 62 </plugins> 63 </build> 64 65 <repositories> 66 <repository> 67 <id>spring-milestones</id> 68 <name>Spring Milestones</name> 69 <url>https://repo.spring.io/milestone</url> 70 <snapshots> 71 <enabled>false</enabled> 72 </snapshots> 73 </repository> 74 </repositories> 75 </project>
3. 創建啟動類: 使用@EnableZuulProxy注解
1 package spring.helloworld.zuul.service; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 7 8 @EnableZuulProxy 9 @EnableEurekaClient 10 @SpringBootApplication 11 public class ServiceZuulApplication { 12 public static void main(String[] args) { 13 SpringApplication.run(ServiceZuulApplication.class, args); 14 } 15 }
4. 編寫zuul服務配置:
簡單配置兩個路由, 一個路由到ribbon,一個路由到feign; 由於都注冊到eureka服務中心,所以都用通過serviceId來發現服務具體地址, path是路由的地址映射關系
1 eureka: 2 client: 3 serviceUrl: 4 defaultZone: http://localhost:8761/eureka/ 5 server: 6 port: 8904 7 spring: 8 application: 9 name: service-zuul 10 zuul: 11 routes: 12 ribbo: 13 path: /api-ribbon/** 14 serviceId: service-ribbon 15 feign: 16 path: /api-feign/** 17 serviceId: service-feign
這時啟動zuul服務, 然后訪問http://localhost:8904/api-ribbon可直接路由到http://localhost:8901/.
http://localhost:8904/api-feign/hello可路由到http://localhost:8902/hello
5. Zuul過濾器
zuul還提供了過濾功能, 只要實現接口ZuulFilter即可對請求先進行篩選和過濾之后再路由到具體服務。
1 package spring.helloworld.zuul.service; 2 3 import javax.servlet.http.HttpServletRequest; 4 5 import org.slf4j.Logger; 6 import org.slf4j.LoggerFactory; 7 import org.springframework.stereotype.Component; 8 9 import com.netflix.zuul.ZuulFilter; 10 import com.netflix.zuul.context.RequestContext; 11 12 @Component 13 public class DemoFilter extends ZuulFilter { 14 private static Logger log = LoggerFactory.getLogger(DemoFilter.class); 15 @Override 16 public String filterType() { 17 return "pre"; 18 } 19 20 @Override 21 public int filterOrder() { 22 return 0; 23 } 24 25 @Override 26 public boolean shouldFilter() { 27 return true; 28 } 29 30 @Override 31 public Object run() { 32 RequestContext ctx = RequestContext.getCurrentContext(); 33 HttpServletRequest request = ctx.getRequest(); 34 String s = String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()); 35 log.info(s); 36 return null; 37 } 38 }
filterType:返回一個字符串代表過濾器的類型,在zuul中定義了四種不同生命周期的過濾器類型,具體如下:
- pre:路由之前
- routing:路由之時
- post: 路由之后
- error:發送錯誤調用
filterOrder:過濾的順序
- pre:路由之前
- routing:路由之時
- post: 路由之后
- error:發送錯誤調用
shouldFilter:這里可以寫邏輯判斷,是否要過濾,本文true,永遠過濾。
run:過濾器的具體邏輯,這里只是將請求的URL簡單些到日志中
上一篇:Spring Cloud 入門教程(八): 斷路器指標數據監控Hystrix Dashboard 和 Turbine
下一篇:Spring Cloud 入門教程(十):和RabbitMQ的整合 -- 消息總線Spring Cloud Netflix Bus
