摘要: Spring Cloud对Netflix的Zuul进行封装之后,Spring Cloud Zuul作为Spring Cloud的网关一直被大家使用用至今,在Spring Cloud的核心项目开发者Spencergibb
的一篇博客The API Gateway is Dead! Long Live the API Gateway!中介绍了Zuul,Zuul
2以及为什么会有Spring Cloud Gateway,大家有兴趣可以看一下。本文将会对spring-cloud-gateway-mvc源码进行demo演示和简单分析。
一.Spring Cloud Gateway概况
1.1 什么是Spring Cloud GateWay
A Gateway built on Spring Framework 5.0 and Spring Boot 2.0 providing routing and more。
Spring Cloud Gateway是基于Spring 框架5.0版本和Spring Boot 2.0的版本构建,提供路由等功能。
1.2 Spring Cloud GateWay的功能
Spring Cloud GateWay具有以下特征
- Java 8/Spring 5/Boot 2
- WebFlux/Reactor
- HTTP/2 and Websockets
- Finchley Release Train (Q4 2017)
由于Spring 5.0支持Netty,Http2,而Spring Boot 2.0支持Spring 5.0,因此Spring Cloud Gateway支持Netty和Http2顺理成章。至于2017年Q4季度是否发布完整的Spring Cloud Gateway我们拭目以待。
1.3 Spring Cloud GateWay离开孵化器
从2016年12月份以后,在Github上出现了Spring Cloud Gateway的项目,地址为:github.com/spring-clou…,如下图所示。
Spring Cloud GateWay离开孵化器之后master分支有MVC模块,需要查看完整的其它的模块请切换分支到2.X 。因此在本文不分析core里面的设计和实现,后面将会补一篇文章介绍。
2.Spring Cloud Gateway的设计核心代码主要在spring-cloud-gateway-core,但是由于目前离开孵化器之后spring-cloud-gateway-core的代码挪到了2.X中,点击访问会自动转发到github.com/spring-clou…
如上图所示,目前master分支
中gateway没有core和starter,相对而言增加了一个spring-cloud-gateway-mvc
模块,在下面章节将会对该模块进行demo和源码分析。
1.3 用Spring MVC的方式构建Gateway
1.3.1 How to Include Spring Cloud Gateway
To include Spring Cloud Gateway in your project add a dependency with group org.springframework.cloud and artifact id spring-cloud-gateway-mvc. See the Spring Cloud Project page for details on setting up your build system with the current Spring Cloud Release Train.
使用spring-cloud-gateway-mvc,只要引入对应的spring-cloud-gateway-mvc的依赖坐标。
1.3.2 Building a Gateway Using Spring MVC
Spring Cloud Gateway provides a utility object called ProxyExchange which you can use inside a regular Spring MVC handler as a method parameter. It supports basic downstream HTTP exchanges via methods that mirror the HTTP verbs, or forwarding to a local handler via the forward() method.
Example (proxying a request to “/test” downstream to a remote server):
@RestController
@SpringBootApplication
public class GatewaySampleApplication {
@Value("${remote.home}")
private URI home;
@GetMapping("/test")
public ResponseEntity<?> proxy(ProxyExchange<Object> proxy) throws Exception {
return proxy.uri(home.toString() + "/image/png").get();
}
}
Spring Cloud Gateway 提供了一个实用的对象叫ProxyExchange,你可以用它像使用Spring MVC Handler的方式去转发,重定向构建网关。
更多信息参考:github.com/spring-clou…
二.Spring Cloud Gateway的MVC模块源码分析
2.1 构建Spring Cloud Gateway的Demo
Spring Cloud Gateway的工程里已经给我提供了一个,spring-cloud-gateway-sample的工程,该工程项目依赖于spring-cloud-gateway-mvc,因此要对其源码分析,只需让才sample 正常work就ok。
从工程截图来看,和我之前看的core模块来说,mvc模块只是做了个请求的转发。
2.2 Spring Cloud Gateway模块源码分析
1.在spring-cloud-gateway-sample中application.yml增加应用名和端口配置
server:
port: 8080
spring:
application:
name: sc-gw
management:
security:
enabled: false
remote:
home: http://httpbin.org #请求转发的目标服务Url
2.org.springframework.cloud.gateway.sample.GatewaySampleApplication.java
@RestController
@SpringBootApplication
public class GatewaySampleApplication {
@Value("${remote.home}")
private URI home;
//该方法需要传递head为x-host=png.abc.org方可调用
@GetMapping(path="/test", headers="x-host=png.abc.org")
public ResponseEntity<Object> proxy(ProxyExchange<Object> proxy) throws Exception {
return proxy.uri(home.toString() + "/image/png")
.get(header("X-TestHeader", "foobar"));
}
@GetMapping("/test2")
public ResponseEntity<Object> proxyFoos(ProxyExchange<Object> proxy) throws Exception {
return proxy.uri(home.toString() + "/image/webp").get(header("X-AnotherHeader", "baz"));
}
private Function<ResponseEntity<Object>, ResponseEntity<Object>> header(String key,
String value) {
return response -> ResponseEntity.status(response.getStatusCode())
.headers(response.getHeaders()).header(key, value)
.body(response.getBody());
}
public static void main(String[] args) {
SpringApplication.run(GatewaySampleApplication.class, args);
}
}
2.3 代码分析
- 启动GatewaySampleApplication主应用程序,访问http://localhost:8080/test2,Debug流程如下。
@GetMapping("/test2")
public ResponseEntity<Object> proxyFoos(ProxyExchange<Object> proxy) throws Exception {
return proxy.uri(home.toString() + "/image/webp").get(header("X-AnotherHeader", "baz"));
}
- 在ProxyExchange.java中的237行代码
public ProxyExchange<T> uri(String uri) {
try {
//将uri:http://httpbin.org/image/webp,new URI对象返回
this.uri = new URI(uri);
}
catch (URISyntaxException e) {
throw new IllegalStateException("Cannot create URI", e);
}
return this;
}
在RestTemplate.java中的628行doExecute去使用对应的httpClient实现远程调用
@Override
public <T> T execute(URI url, HttpMethod method, RequestCallback requestCallback,
ResponseExtractor<T> responseExtractor) throws RestClientException {
return doExecute(url, method, requestCallback, responseExtractor);
}
最终调用代码如下图所示,由于源码比较简单,因此有些细节流程略过,有兴趣可以自己跟踪理解。
如果您觉得文章不错,可以打赏我喝一杯咖啡! 您看完此文章的心情是