前言
服务端提供 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