Zuul源码分析之 网关处理流程
Posted 全栈开发Dream
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Zuul源码分析之 网关处理流程相关的知识,希望对你有一定的参考价值。
Zuul 处理流程
一、spring-cloud-starter-zuul starter
-
我们先查看spring-cloud-starter-zuul starter包下有什么,这里的重点就是pom.xml文件,ZuulDeprecationWarningAutoConfiguration.java
-
打开org.springframework.cloud/spring-cloud-starter-zuul/pom.xml ,可以看到是依赖了spring-cloud-starter-netflix-zuul
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-zuul</artifactId>
<name>spring-cloud-starter-zuul</name>
<description>Spring Cloud Starter Zuul (deprecated, please use spring-cloud-starter-netflix-zuul)</description>
<url>https://projects.spring.io/spring-cloud</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>https://www.spring.io</url>
</organization>
<properties>
<main.basedir>$basedir/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
</project>
-
我们查看spring-cloud-starter-netflix-zuul包
-
打开pom.xml可以看到依赖了com.netflix.zuul,所以说Spring Cloud Zuul是基于netflix公司的zuul实现的,除此之外还添加了hystrix及ribbon依赖,所以zuul是自带这两个功能的,spring-boot-starter-web依赖可以使应用成为web应用,spring-boot-starter-actuator是监控依赖
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<name>Spring Cloud Starter Netflix Zuul</name>
<description>Spring Cloud Starter Netflix Zuul</description>
<url>https://projects.spring.io/spring-cloud</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>https://www.spring.io</url>
</organization>
<properties>
<main.basedir>$basedir/../../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-archaius</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.zuul</groupId>
<artifactId>zuul-core</artifactId>
</dependency>
</dependencies>
</project>
- /META-INF/spring.provides 依赖spring-platform-netflix-core模块及zuul-core模块
1 provides: spring-platform-netflix-core, zuul-core
- 现在我们进入spring-platform-netflix-core,看看Spring是怎样集成Netflix的一系列框架了,下面是代码框架图
- 可以看到这个JAR包也包含了spring.factories文件,所以SpringBoot项目启动的时候会检索此配置文件,此文件是zuul实现自动注册配置的关键,下面可以看到熟悉的zuul,hystrix,feign,ribbon的自动配置类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration,\\
org.springframework.cloud.netflix.feign.ribbon.FeignRibbonClientAutoConfiguration,\\
org.springframework.cloud.netflix.feign.FeignAutoConfiguration,\\
org.springframework.cloud.netflix.feign.encoding.FeignAcceptGzipEncodingAutoConfiguration,\\
org.springframework.cloud.netflix.feign.encoding.FeignContentGzipEncodingAutoConfiguration,\\
org.springframework.cloud.netflix.hystrix.HystrixAutoConfiguration,\\
org.springframework.cloud.netflix.hystrix.security.HystrixSecurityAutoConfiguration,\\
org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration,\\
org.springframework.cloud.netflix.rx.RxJavaAutoConfiguration,\\
org.springframework.cloud.netflix.metrics.servo.ServoMetricsAutoConfiguration,\\
org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration,\\
org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration
org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\\
org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration
org.springframework.boot.env.EnvironmentPostProcessor=\\
org.springframework.cloud.netflix.metrics.ServoEnvironmentPostProcessor
-
我们现在关心Zuul的自动配置类,从上面spring.factories文件可以看到和Zuul相关的是自动配置了两个类,下图可以看到这两个有继承关系,ZuulProxyAutoConfiguration功能最为完全
-
ZuulServerAutoConfiguration 与 ZuulProxyAutoConfiguration
-
ZuulServerAutoConfiguration自动配置类,启动类上如果有@EnableZuulServer则此类生效
1.下面代码可以看到大量使用了@Conditional作为条件判断,注意这个ZuulController这个Bean,它是Zuul的请求入口,这个类实现了Controller了,说明这里也使用了Spring MVC DispatcherServlet,
2.同时此类注册了大量的ZuulFilter
3.代码:
/**
* @author
*/
@Configuration // 声明是配置类
@EnableConfigurationProperties( ZuulProperties.class ) // 激活 zuul配置
@ConditionalOnClass(ZuulServlet.class) // 条件1 存在ZuulServlet.class
@ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class) // 条件2 存在ZuulServerMarkerConfiguration.Marker.class bean, 即应用使用@EnableZuulServer注解
// Make sure to get the ServerProperties from the same place as a normal web app would
@Import(ServerPropertiesAutoConfiguration.class) // 配置ServerProperties实例
public class ZuulServerAutoConfiguration
@Autowired
protected ZuulProperties zuulProperties;
@Autowired
protected ServerProperties server;
@Autowired(required = false)
private ErrorController errorController;
@Bean
public HasFeatures zuulFeature()
return HasFeatures.namedFeature("Zuul (Simple)", ZuulServerAutoConfiguration.class);
@Bean
@Primary
public CompositeRouteLocator primaryRouteLocator(
Collection<RouteLocator> routeLocators)
return new CompositeRouteLocator(routeLocators);
@Bean
@ConditionalOnMissingBean(SimpleRouteLocator.class)
public SimpleRouteLocator simpleRouteLocator()
return new SimpleRouteLocator(this.server.getServletPrefix(),
this.zuulProperties);
/**
* zuulController, 包装了一个ZuulServlet类型的servlet, 实现对ZuulServlet类型的servlet的初始化.
*
* @return
*/
@Bean
public ZuulController zuulController()
return new ZuulController();
@Bean
public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes)
ZuulHandlerMapping mapping = new ZuulHandlerMapping(routes, zuulController());
mapping.setErrorController(this.errorController);
return mapping;
@Bean
public ApplicationListener<ApplicationEvent> zuulRefreshRoutesListener()
return new ZuulRefreshListener();
@Bean
@ConditionalOnMissingBean(name = "zuulServlet")
public ServletRegistrationBean zuulServlet()
ServletRegistrationBean servlet = new ServletRegistrationBean(new ZuulServlet(),
this.zuulProperties.getServletPattern());
// The whole point of exposing this servlet is to provide a route that doesn't
// buffer requests.
servlet.addInitParameter("buffer-requests", "false");
return servlet;
// pre filters
@Bean
public ServletDetectionFilter servletDetectionFilter()
return new ServletDetectionFilter();
@Bean
public FormBodyWrapperFilter formBodyWrapperFilter()
return new FormBodyWrapperFilter();
@Bean
public DebugFilter debugFilter()
return new DebugFilter();
@Bean
public Servlet30WrapperFilter servlet30WrapperFilter()
return new Servlet30WrapperFilter();
// post filters
@Bean
public SendResponseFilter sendResponseFilter()
return new SendResponseFilter();
@Bean
public SendErrorFilter sendErrorFilter()
return new SendErrorFilter();
@Bean
public SendForwardFilter sendForwardFilter()
return new SendForwardFilter();
@Bean
@ConditionalOnProperty(value = "zuul.ribbon.eager-load.enabled", matchIfMissing = false)
public ZuulRouteApplicationContextInitializer zuulRoutesApplicationContextInitiazer(
SpringClientFactory springClientFactory)
return new ZuulRouteApplicationContextInitializer(springClientFactory,
zuulProperties);
@Configuration
protected static class ZuulFilterConfiguration
@Autowired
private Map<String, ZuulFilter> filters;
@Bean
public ZuulFilterInitializer zuulFilterInitializer(
CounterFactory counterFactory, TracerFactory tracerFactory)
FilterLoader filterLoader = FilterLoader.getInstance();
FilterRegistry filterRegistry = FilterRegistry.instance();
return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry);
@Configuration
@ConditionalOnClass(CounterService.class)
protected static class ZuulCounterFactoryConfiguration
@Bean
@ConditionalOnBean(CounterService.class)
public CounterFactory counterFactory(CounterService counterService)
return new DefaultCounterFactory(counterService);
@Configuration
protected static class ZuulMetricsConfiguration
@Bean
@ConditionalOnMissingBean(CounterFactory.class)
public CounterFactory counterFactory()
return new EmptyCounterFactory();
@ConditionalOnMissingBean(TracerFactory.class)
@Bean
public TracerFactory tracerFactory()
return new EmptyTracerFactory();
private static class ZuulRefreshListener
implements ApplicationListener<ApplicationEvent>
@Autowired
private ZuulHandlerMapping zuulHandlerMapping;
private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor();
@Override
public void onApplicationEvent(ApplicationEvent event)
if (event instanceof ContextRefreshedEvent
|| event instanceof RefreshScopeRefreshedEvent
|| event instanceof RoutesRefreshedEvent)
this.zuulHandlerMapping.setDirty(true);
else if (event instanceof HeartbeatEvent)
if (this.heartbeatMonitor.update(((HeartbeatEvent) event).getValue()))
this.zuulHandlerMapping.setDirty(true);
- ZuulProxyAutoConfiguration自动配置类,启动类上如果有对应@EnableZuulProxy则此类生效
- 由上面此类的继承图可以发现这个类继承了ZuulServerAutoConfiguration,所以此类拥有ZuulServerAutoConfiguration的所有功能,并在此基础上添加了使用了服务发现作为路由寻址功能
- 代码:
/**
* @author
*/
@Configuration // 声明是配置类
@Import( RibbonCommandFactoryConfiguration.RestClientRibbonConfiguration.class, // 引入RibbonCommandFactory配置
RibbonCommandFactoryConfiguration.OkHttpRibbonConfiguration.class,
RibbonCommandFactoryConfiguration.HttpClientRibbonConfiguration.class,
HttpClientConfiguration.class )
@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class) // 条件2 存在ZuulProxyMarkerConfiguration.Marker.class bean, 即应用使用@EnableZuulProxy注解
public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration
@SuppressWarnings("rawtypes")
@Autowired(required = false)
private List<RibbonRequestCustomizer> requestCustomizers = Collections.emptyList();
/**
* 网关服务注册实例信息
*/
@Autowired(required = false)
private Registration registration;
/**
* 服务发现客户端
*/
@Autowired
private DiscoveryClient discovery;
/**
* serviceId和路由的映射逻辑
*/
@Autowired
private ServiceRouteMapper serviceRouteMapper;
@Override
public HasFeatures zuulFeature()
return HasFeatures.namedFeature("Zuul (Discovery)",
ZuulProxyAutoConfiguration.class);
/**
* 静态和动态路由寻址: 静态从配置文件获取, 动态通过服务发现客户端完成. 后者优先级更高
* @return
*/
@Bean
@ConditionalOnMissingBean(DiscoveryClientRouteLocator.class)
public DiscoveryClientRouteLocator discoveryRouteLocator()
return new DiscoveryClientRouteLocator(this.server.getServletPrefix(),
this.discovery, this.zuulProperties, this.serviceRouteMapper, this.registration);
// pre filters
@Bean
public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator,
ProxyRequestHelper proxyRequestHelper)
return new PreDecorationFilter(routeLocator, this.server.getServletPrefix(),
this.zuulProperties, proxyRequestHelper);
以上是关于Zuul源码分析之 网关处理流程的主要内容,如果未能解决你的问题,请参考以下文章