前言
服務端提供 RestFul API ,客戶端如果想要使用某個服務直接調用服務的API 即可。但是在微服務環境中會有很多的具體服務,而客戶端在需要使用衆多的服務時在和具體的服務打交道這樣雖然可以實現但是處理方式並不是很好。而服務網關就是用來專門解決這一個問題的。
有了網關後可以將各個服務的API 都接入到網關中,客戶端直接調用網關即可。同時對於業務功能需要多個服務進行參與也可一通過服務網關進行聚合。在有就是引入網關後可以將安全驗證、用戶權限驗證、服務流量控制統一在網關層做處理,無需每個服務在獨自做這些操作。
目前開源的服務網關有:Kong、Zuul/Zuul2、OpenResty、Tyk。我們今天要介紹的就是SpringCloud 集成 Netflix 的開源網關Zuul 1 使用的簡單介紹。
閱讀本文需要你熟悉SpringBoot項目的基本使用即可,還有一點需要注意的是在操作過程中儘量和我本地環境一致,因爲環境不一致可能會帶來一些問題。我本地環境如下:
- SpringBoot Version: 2.1.0.RELEASE
- SpringCloud Version: Greenwich.RELEASE
- Apache Maven Version: 3.6.0
- Java Version: 1.8.0_144
- IDEA:Spring Tools Suite (STS)
Zuul 的簡單介紹
Zuul 核心是通過一系列的過濾器來完成整個網關的操作,具體過濾器有如下4中:
- PRE :前置過濾器,在調用具體服務前執行,常見的操作如:身份驗證,安全校驗
- ROUTING:路由過濾器,它的作用是將訪問網關的請求路由到具體的服務。
- POST:後置過濾器,在調用服務後執行。常見的操作如:統計訪問請求、請求日誌
- ERROR:錯誤過濾器,當調用服務發生錯誤是執行。
Zuul 服務請求聲明週期流程如下圖:
SpringCloud Zuul 環境搭建
SpringCloud Zuul 環境最小配置列表如下:
- 一臺 Eureka Server 端
- 一臺具體服務端(用戶服務)
- 一臺 Zuul 服務端
其中具體服務端 和 Zuul 服務端 同時也是 Eureka Client 端。
第一步:是搭建 Eureka Server 端環境,關於如果搭建Eureka Server 端環境請參考:帶你入門SpringCloud服務發現 |Eurka搭建和使用 或者直接使用 spring-cloud-get-started 倉庫中模塊名爲:spring-cloud-zuul-eureka-service 項目即可。
第二步:需要在 Zuul SpringCloud 服務端引入 Eureka 和 Zuul 的 starter 依賴,具體代碼入下:
<?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 https://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.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.zhuoqianmingyue</groupId>
<artifactId>spring-cloud-zuul-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-zuul-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
<finalName>zuulService</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>
第三步:在 Zuul 服務 啓動類上聲明 @EnableZuulProxy 註解
@SpringBootApplication
@EnableZuulProxy
public class SpringCloudZuulServiceApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudZuulServiceApplication.class, args);
}
}
第四步:在 Zuul 服務 application.properties 中添加入下配置:
spring.application.name=api-gateway
server.port=8060
eureka.client.service-url.defaultZone=http://127.0.0.1:8761/eureka/
- spring.application.name: Zuul 服務的名稱
- server.port:Zuul 服務端口
- eureka.client.service-url.defaultZone:Eureka Server 服務端地址
第五步:搭建具體服務端(用戶服務)環境。
用戶服務 pom.xml 具體配置如下:
<?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 https://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.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.zhuoqianmingyue</groupId>
<artifactId>spring-cloud-zuul-user-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-zuul-user-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
<finalName>zuulUserService</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>
用戶服務增刪改查API服務接口類具體代碼如下:
@RestController()
@RequestMapping("/user")
public class UserController {
Logger log = LoggerFactory.getLogger(UserController.class);
/**
* 根據用戶id 查詢用戶
* @return
*/
@GetMapping("/{id}")
public ResponseEntity<User> get(@PathVariable(name = "id") Long id){
User user = new User("lijunkui",18);
log.info("查詢用戶成功:"+"id:{}",id);
return ResponseEntity.ok(user);
}
/**
* 查詢所有的用戶
* @return
*/
@GetMapping("/")
public ResponseEntity<List<User>> getAll(){
List<User> userList = new ArrayList<User>(){{
add(new User("lijunkui1",18));
add(new User("lijunkui2",18));
add(new User("lijunkui3",18));
}};
return ResponseEntity.ok(userList);
}
/**
* 添加用戶
*/
@PostMapping("/")
public ResponseEntity<User> add(@RequestBody User user){
log.info("添加用戶成功:"+"name:{},age:{}",user.getName(),user.getAge());
return ResponseEntity.status(HttpStatus.CREATED).body(user);
}
/**
* 更新用戶
* @param user
* @return
*/
@PutMapping("/")
public ResponseEntity<Void> updatePut(@RequestBody User user){
log.info("修改用戶成功:"+"name:{},age:{}",user.getName(),user.getAge());
return ResponseEntity.ok().build();
}
/**
* 局部更新
* @return
*/
@PatchMapping("/{name}")
public ResponseEntity<Void> updatePatch(@PathVariable("name") String name){
log.info("修改用戶成功:"+"name:{}",name);
return ResponseEntity.ok().build();
}
/**
* 刪除用戶
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable("id") Long id){
log.info("刪除用戶成功:"+"id:{}",id);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
}
因爲用戶服務同時是 Eureka Client 所以在啓動類上聲明 @EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudZuulUserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudZuulUserServiceApplication.class, args);
}
}
用戶服務端 application.properties 中配置內容如下:
spring.application.name=USER
server.servlet.context-path=/userService
server.port=8763
eureka.client.service-url.defaultZone=http://127.0.0.1:8761/eureka/
到這裏最簡 Zuul 環境搭建完畢!
關於Zuul 高可用用直接搭建多個 Zuul 服務註冊到 Eureka Server 端即可。如果你想讓Zuul 服務實現動態路由,搭建Zuul 服務 SpringCloud Config 環境即可。具體操作請參考
測試
首先啓動 Eureka Server 端,然後在啓動具體服務端(用戶服務)和 Zuul 服務端。
訪問 用戶服務 鏈接地址:http://localhost:8763/userService/user/,具體效果如下圖:
訪問 Zuul 服務 鏈接地址:http://localhost:8060/user/userService/user/,具體效果如下圖:
通過Zuul 訪問具體服務規則 Zuul 服務 ip+Zuul服務端口號+訪問服務名稱+訪問服務 Api 地址
在 application.properties 通過 spring.application.name 配置訪問服務名稱,還有一點要注意的是服務名稱只能使用小寫。
小結
Zuul 環境搭建大致步驟如下:
- 引入 Eureka 和 Zuul 的 starter 依賴
- 啓動類上聲明 @EnableZuulProxy 註解
- 配置文件中配置 Eureka Server 地址
當然還需要搭建 Eureka Server 環境 和具體服務的環境,本文主要介紹 Zuul 環境搭建和簡單使用,後面會陸續講解 Zuul 具體的使用。
代碼示例
如果你按照上述方式搭建並未成功,可以參考我在GitHub 項目 spring-cloud-get-started 倉庫中模塊名爲:
- spring-cloud-zuul-eureka-service
- spring-cloud-zuul-service
- spring-cloud-zuul-user-service
進行對比查看是否配置有誤。
spring-cloud-get-started 項目地址:https://github.com/zhuoqianmingyue/spring-cloud-get-started
參考文獻
- https://github.com/Netflix/zuul/wiki
- https://medium.com/netflix-techblog/announcing-zuul-edge-service-in-the-cloud-ab3af5be08ee