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.ZuulProxyAutoConfigurationorg.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfigurationorg.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);    }    // route filters    @Bean    public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper,            RibbonCommandFactory<?> ribbonCommandFactory) {        RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory,                this.requestCustomizers);        return filter;    }    @Bean    @ConditionalOnMissingBean({SimpleHostRoutingFilter.class, CloseableHttpClient.class})    public SimpleHostRoutingFilter simpleHostRoutingFilter(ProxyRequestHelper helper,            ZuulProperties zuulProperties,            ApacheHttpClientConnectionManagerFactory connectionManagerFactory,            ApacheHttpClientFactory httpClientFactory) {        return new SimpleHostRoutingFilter(helper, zuulProperties,                connectionManagerFactory, httpClientFactory);    }    @Bean    @ConditionalOnMissingBean({SimpleHostRoutingFilter.class})    public SimpleHostRoutingFilter simpleHostRoutingFilter2(ProxyRequestHelper helper,                                                           ZuulProperties zuulProperties,                                                           CloseableHttpClient httpClient) {        return new SimpleHostRoutingFilter(helper, zuulProperties,                httpClient);    }    @Bean    public ApplicationListener<ApplicationEvent> zuulDiscoveryRefreshRoutesListener() {        return new ZuulDiscoveryRefreshListener();    }    @Bean    @ConditionalOnMissingBean(ServiceRouteMapper.class)    public ServiceRouteMapper serviceRouteMapper() {        return new SimpleServiceRouteMapper();    }    @Configuration    @ConditionalOnMissingClass("org.springframework.boot.actuate.endpoint.Endpoint")    protected static class NoActuatorConfiguration {        @Bean        public ProxyRequestHelper proxyRequestHelper(ZuulProperties zuulProperties) {            ProxyRequestHelper helper = new ProxyRequestHelper();            helper.setIgnoredHeaders(zuulProperties.getIgnoredHeaders());            helper.setTraceRequestBody(zuulProperties.isTraceRequestBody());            return helper;        }    }    /**     * 增加 Endpoint     */    @Configuration    @ConditionalOnClass(Endpoint.class)    protected static class EndpointConfiguration {        @Autowired(required = false)        private TraceRepository traces;        @ConditionalOnEnabledEndpoint("routes")        @Bean        public RoutesEndpoint routesEndpoint(RouteLocator routeLocator) {            return new RoutesEndpoint(routeLocator);        }        @ConditionalOnEnabledEndpoint("routes")        @Bean        public RoutesMvcEndpoint routesMvcEndpoint(RouteLocator routeLocator,                RoutesEndpoint endpoint) {            return new RoutesMvcEndpoint(endpoint, routeLocator);        }        @ConditionalOnEnabledEndpoint("filters")        @Bean        public FiltersEndpoint filtersEndpoint() {            FilterRegistry filterRegistry = FilterRegistry.instance();            return new FiltersEndpoint(filterRegistry);        }        @Bean        public ProxyRequestHelper proxyRequestHelper(ZuulProperties zuulProperties) {            TraceProxyRequestHelper helper = new TraceProxyRequestHelper();            if (this.traces != null) {                helper.setTraces(this.traces);            }            helper.setIgnoredHeaders(zuulProperties.getIgnoredHeaders());            helper.setTraceRequestBody(zuulProperties.isTraceRequestBody());            return helper;        }    }    private static class ZuulDiscoveryRefreshListener            implements ApplicationListener<ApplicationEvent> {        private HeartbeatMonitor monitor = new HeartbeatMonitor();        @Autowired        private ZuulHandlerMapping zuulHandlerMapping;        @Override        public void onApplicationEvent(ApplicationEvent event) {            if (event instanceof InstanceRegisteredEvent) {                reset();            }            else if (event instanceof ParentHeartbeatEvent) {                ParentHeartbeatEvent e = (ParentHeartbeatEvent) event;                resetIfNeeded(e.getValue());            }            else if (event instanceof HeartbeatEvent) {                HeartbeatEvent e = (HeartbeatEvent) event;                resetIfNeeded(e.getValue());            }        }        private void resetIfNeeded(Object value) {            if (this.monitor.update(value)) {                reset();            }        }        private void reset() {            this.zuulHandlerMapping.setDirty(true);        }    }}
  • ZuulServerAutoConfiguration 与 ZuulProxyAutoConfiguration具体应用哪种模式,是别离通过@EnableZuulServer 和@EnableZuulProxy注解来区别的
  • 前者应用了ZuulProperties进行配置路由寻址;
  • 后者在原来的根底上增加了应用了服务发现作为路由寻址性能, 并应用Ribbon做客户端的负载平衡,这个最为罕用

二、@EnableZuulProxy

  • @EnableZuulProxy注解
/** * Sets up a Zuul server endpoint and installs some reverse proxy filters in it, so it can * forward requests to backend servers. The backends can be registered manually through * configuration or via DiscoveryClient. * * @see EnableZuulServer for how to get a Zuul server without any proxying * * @author */@EnableCircuitBreaker@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Import(ZuulProxyMarkerConfiguration.class)public @interface EnableZuulProxy {}
  • @EnableZuulProxy剖析
  • @EnableCircuitBreaker注解用于开启短路器性能
/** * Annotation to enable a CircuitBreaker implementation. * http://martinfowler.com/bliki/CircuitBreaker.html * @author */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(EnableCircuitBreakerImportSelector.class)public @interface EnableCircuitBreaker {}
  • @Import(ZuulProxyMarkerConfiguration.class)
  • ZuulProxyMarkerConfiguration.Marker.class
@Configurationpublic class ZuulProxyMarkerConfiguration {    @Bean    public Marker zuulProxyMarkerBean() {        return new Marker();    }    class Marker {    }}

三、应用Consul作为注册核心

  • @EnableZuulProxy模式下的zuul须要注册核心的反对,因为eureka曾经被抛弃了,我这里选用的是Consul

1.增加Maven依赖

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency>

2.启动类上加上@EnableDiscoveryClient注解

@EnableZuulProxy@EnableDiscoveryClient@SpringBootApplicationpublic class ZuulApplication {    public static void main(String[] args) {        SpringApplication.run(ZuulApplication.class, args);    }}

3.通过以上所有步骤后,整个服务网关Zuul利用就能够发挥作用了

四、总结

1.Spring Cloud对Netflix Zuul做了封装集成, 使得在Spring Cloud环境中应用Zuul更不便,只需增加spring-cloud-starter-zuul maven依赖及启动类上增加@EnableZuulProxy就可创立一个zuul利用。
2.Spring Cloud Zuul 实际上就是在Servlet的根底上增加了一些ZuulFilter去实现一些额定事件,封装了就成框架了。