Spring cloud学习之Zuul入门篇

最近需要做一次分享,简单的demo肯定拿不出来,因此打算看看源码弄清楚Zuul的一次转发

准备工作(本文使用的Spring cloud版本是Greenwich:SR1):

注册中心、zuul网关、具体后端服务

先搭建这几个服务:

以上是建一个空maven工程,用做父工程,接下来搭建eureka-server

若出现jar无法导入的情况,在父工程pom.xml中加入

<modules>
    <module>eureka-server</module>
</modules>

习惯用yml做配置文件,修改application.properties文件后缀为.yml(可以不修改,不修改就使用properties的key=value形式配置)

# 端口
server:
  port: 9000

spring:
  application:
    name: eureka-server

# eureka配置
eureka:
  client:
    fetchRegistry: false
    registerWithEureka: false
    serviceUrl:
      defaultZone: http://localhost:${server.port}/eureka/

在主启动类上加上注解@EnableEurekaServer

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaServerApplication.class, args);
	}

}

接下来搭建后端服务

在父工程pom.xml加入module

    <modules>
        <module>eureka-server</module>
        <module>service-a</module>
    </modules>

修改配置文件、主启动类

# 端口
server:
  port: 9001

spring:
  application:
    name: service-a
# eureka
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
@EnableEurekaClient
@SpringBootApplication
public class ServiceAApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceAApplication.class, args);
    }

}

提供一个接口供测试用:

@RestController
public class TestController {

    @GetMapping("/hello")
    public void hello() {
        System.out.println("hello spring cloud!");
    }

}

Zuul网关服务器

同样使用Spring initializr创建zuul-demo服务,勾选服务时选择

修改properties属性文件为yml,同时加入一下配置

# 端口
server:
  port: 9002

spring:
  application:
    name: zuul-demo
# eureka
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
# zuul配置
zuul:
  routes:
    rules1:
      serviceId: service-a
      path: /api-a/**
@RestController
public class TestController {

    @GetMapping("/hello")
    public String hello() {
        return "hello spring cloud!";
    }

}

启动这3个工程,用postman、或者浏览器访问http://localhost:9002/api-a/hello

接下来通过看源码来看看一次转发zuul做来哪些事情

先看下zuul配置类ZuulProxyAutoConfiguration

注意红框内等2个过滤器,一个前置过滤器,一个路由过滤器,先重点看看路由过滤器RibbonRoutingFilter,看看这个过滤器的run()方法

	@Override
	public Object run() {
		RequestContext context = RequestContext.getCurrentContext();
		this.helper.addIgnoredHeaders();
		try {
			RibbonCommandContext commandContext = buildCommandContext(context);
			ClientHttpResponse response = forward(commandContext);
			setResponse(response);
			return response;
		}
		catch (ZuulException ex) {
			throw new ZuulRuntimeException(ex);
		}
		catch (Exception ex) {
			throw new ZuulRuntimeException(ex);
		}
	}

run()方法调用来一个forward()方法,再来看看forward()方法

	protected ClientHttpResponse forward(RibbonCommandContext context) throws Exception {
		Map<String, Object> info = this.helper.debug(context.getMethod(),
				context.getUri(), context.getHeaders(), context.getParams(),
				context.getRequestEntity());

		RibbonCommand command = this.ribbonCommandFactory.create(context);
		try {
			ClientHttpResponse response = command.execute();
			this.helper.appendDebug(info, response.getRawStatusCode(),
					response.getHeaders());
			return response;
		}
		catch (HystrixRuntimeException ex) {
			return handleException(info, ex);
		}

	}

ribbonCommandFactory.create(context)实际是调用HttpClientRibbonCommandFactory类中的create方法(我是怎么知道的,咳咳。。笨方法,将所有实现类打断点,调用时进入哪个就知道类)。看看此类的create方法

从字面上理解,FallbackProvider zuulFallbackProvider = getFallbackProvider(context.getServiceId());是获取serviceId下的所有熔断降级处理方法。final RibbonLoadBalancingHttpClient client = this.clientFactory.getClient(serviceId, RibbonLoadBalancingHttpClient.class);是创建一个httpClient用来执行调用服务并获取响应。client.setLoadBalancer(this.clientFactory.getLoadBalancer(serviceId));设置负载均衡。最后创建了一个HttpClientRibbonCommand返回。

证实刚刚猜测-创建一个httpClient,可以看到RibbonLoadBalancingHttpClient继承AbstractLoadBalancingClient

再看看CloseableHttpClient类

接下来看看ClientHttpResponse response = command.execute();具体实现是哪个类的方法。上面已经知道command实际是HttpClientRibbonCommand,来看看command.extcute()

HttpClientRibbonCommand没有execute方法,前面说过httpClient实际是执行调用方法的,直接RibbonLoadBalancingHttpClient查看,果然找到来execute()方法,看看该方法做了什么

封装参数执行转发并获取响应 this.delegate.execute()

上面方法主要做的就是组装请求参数(包括各种超时时间),然后发起转发请求,最终获取相应结果。

总结:

•Zuul转发一次请求原理

1、zuul的转发是通过RibbonRoutingFilter这个Filter进行操作的。

2、在转发之前,zuul利用Hystrix将此次转发请求包装成一个HystrixCommand,这样使得zuul具有了降级(Fallback)的功能

3、在HystrixCommand内部zuul再次将请求包装成一个Observable,(有关RxJava的知识请参照其官方文档)。在观察者模式下调用httpClient执行

发布了43 篇原创文章 · 获赞 13 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_41070393/article/details/90548300
今日推荐