Spring Cloud Gateway离开孵化器的变化

1,638
原文链接: xujin.org
文章目录
  1. 一.Spring Cloud Gateway概况
    1. 1.1 什么是Spring Cloud GateWay
    2. 1.2 Spring Cloud GateWay的功能
    3. 1.3 Spring Cloud GateWay离开孵化器
    4. 1.3 用Spring MVC的方式构建Gateway
      1. 1.3.1 How to Include Spring Cloud Gateway
      2. 1.3.2 Building a Gateway Using Spring MVC
  2. 二.Spring Cloud Gateway的MVC模块源码分析
    1. 2.1 构建Spring Cloud Gateway的Demo
    2. 2.2 Spring Cloud Gateway模块源码分析
    3. 2.3 代码分析

摘要: 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 代码分析

@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);
}

最终调用代码如下图所示,由于源码比较简单,因此有些细节流程略过,有兴趣可以自己跟踪理解。

如果您觉得文章不错,可以打赏我喝一杯咖啡! 您看完此文章的心情是