Zuul processing process

A, spring – the cloud – starter – zuul starter

  • We check the spring – the cloud – starter – zuul starter what’s under the package, the key here is pom. The XML file, ZuulDeprecationWarningAutoConfiguration. Java

  • Open the org. Springframework. Cloud/spring — cloud – starter – zuul/pom. XML, you can see is dependent on the spring – the 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>Copy the code
  • We look at the Spring-cloud-starter-Netflix-Zuul package

  • When you open pop. XML, you can see that it relies on Com.net Flix. Zuul, so Spring Cloud Zuul is implemented based on Netflix’s Zuul. In addition, Hystrix and Ribbon are added, so Zuul comes with these two functions. The spring-boot-starter- Web dependence enables applications to become Web applications, and the Spring-boot-starter -actuator uses monitoring

<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>Copy the code
  • Provides/meta-inf /spring.provides provides the spring-platform-Netflix-core module and zuul-core module1 provides: spring-platform-netflix-core, zuul-core
  • Now let’s go to Spring-platform-Netflix-core and see how Spring integrates the Netflix framework
  • You can see that the JAR package also contains the spring.Factories file, which is retrieved when the SpringBoot project starts. This file is key to zuul’s automatic registration configuration. You can see below familiar zuul, hystrix, feign, automatic configuration of ribbon class
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
Copy the code
  • We are now concerned about Zuul automatic configuration classes, from the spring. The above factories related files can be seen and Zuul is automatically configured for two classes, below you can see the two have inheritance relationship, ZuulProxyAutoConfiguration function most completely

  • ZuulServerAutoConfiguration and ZuulProxyAutoConfiguration

  • ZuulServerAutoConfiguration automatic configuration, start on if there are @ EnableZuulServer such effect

Note the ZuulController Bean, which is the Zuul request entry. This class implements Controller. Spring MVC DispatcherServlet is also used here. At the same time, this class registers a large number of ZuulFilter 3.

/ * * *@author* /
@Configuration // The declaration is a configuration class
@EnableConfigurationProperties({ ZuulProperties.class }) // Activate zuul configuration
@ConditionalOnClass(ZuulServlet.class) // Condition 1 exists zuulservlet.class
@ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class) / / condition 2 ZuulServerMarkerConfiguration. Marker. Class bean, namely the application using the @ EnableZuulServer annotation
// Make sure to get the ServerProperties from the same place as a normal web app would
@Import(ServerPropertiesAutoConfiguration.class) // Configure the ServerProperties instance
public class ZuulServerAutoConfiguration {

    @Autowired
    protected ZuulProperties zuulProperties;

    @Autowired
    protected ServerProperties server;

    @Autowired(required = false)
    private ErrorController errorController;

    @Bean
    public HasFeatures zuulFeature(a) {
        return HasFeatures.namedFeature("Zuul (Simple)", ZuulServerAutoConfiguration.class);
    }

    @Bean
    @Primary
    public CompositeRouteLocator primaryRouteLocator( Collection
       
         routeLocators)
        {
        return new CompositeRouteLocator(routeLocators);
    }

    @Bean
    @ConditionalOnMissingBean(SimpleRouteLocator.class)
    public SimpleRouteLocator simpleRouteLocator(a) {
        return new SimpleRouteLocator(this.server.getServletPrefix(),
                this.zuulProperties);
    }

    /** * zuulController, which wraps a servlet of type ZuulServlet to initialize a servlet of type ZuulServlet@return* /
    @Bean
    public ZuulController zuulController(a) {
        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(a) {
        return new ZuulRefreshListener();
    }

    @Bean
    @ConditionalOnMissingBean(name = "zuulServlet")
    public ServletRegistrationBean zuulServlet(a) {
        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(a) {
        return new ServletDetectionFilter();
    }

    @Bean
    public FormBodyWrapperFilter formBodyWrapperFilter(a) {
        return new FormBodyWrapperFilter();
    }

    @Bean
    public DebugFilter debugFilter(a) {
        return new DebugFilter();
    }

    @Bean
    public Servlet30WrapperFilter servlet30WrapperFilter(a) {
        return new Servlet30WrapperFilter();
    }

    // post filters

    @Bean
    public SendResponseFilter sendResponseFilter(a) {
        return new SendResponseFilter();
    }

    @Bean
    public SendErrorFilter sendErrorFilter(a) {
        return new SendErrorFilter();
    }

    @Bean
    public SendForwardFilter sendForwardFilter(a) {
        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 newDefaultCounterFactory(counterService); }}@Configuration
    protected static class ZuulMetricsConfiguration {

        @Bean
        @ConditionalOnMissingBean(CounterFactory.class)
        public CounterFactory counterFactory(a) {
            return new EmptyCounterFactory();
        }

        @ConditionalOnMissingBean(TracerFactory.class)
        @Bean
        public TracerFactory tracerFactory(a) {
            return newEmptyTracerFactory(); }}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);
                }
            }
        }

    }

}
Copy the code
  • ZuulProxyAutoConfiguration automatic configuration, start on if there are corresponding @ EnableZuulProxy such effect
  • By the above such inheritance diagrams can find this class inherits ZuulServerAutoConfiguration, so it has ZuulServerAutoConfiguration all functions, and based on this added using the function of service discovery as routing addressing
  • Code:
/ * * *@author* /
@Configuration // The declaration is a configuration class
@Import({ RibbonCommandFactoryConfiguration.RestClientRibbonConfiguration.class, / / introduce RibbonCommandFactory configuration RibbonCommandFactoryConfiguration. OkHttpRibbonConfiguration. Class, RibbonCommandFactoryConfiguration.HttpClientRibbonConfiguration.class, HttpClientConfiguration.class })
@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class) / / condition 2 ZuulProxyMarkerConfiguration. Marker. Class bean, namely the application using the @ EnableZuulProxy annotation
public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration {

    @SuppressWarnings("rawtypes")
    @Autowired(required = false)
    private List<RibbonRequestCustomizer> requestCustomizers = Collections.emptyList();

    /** * Gateway service registration instance information */
    @Autowired(required = false)
    private Registration registration;

    /** * Service discovery client */
    @Autowired
    private DiscoveryClient discovery;

    /** * Mapping logic between serviceId and route */
    @Autowired
    private ServiceRouteMapper serviceRouteMapper;

    @Override
    public HasFeatures zuulFeature(a) {
        return HasFeatures.namedFeature("Zuul (Discovery)",
                ZuulProxyAutoConfiguration.class);
    }

    /** * Static and dynamic routing addressing: static is obtained from the configuration file, and dynamic is done through the service discovery client. The latter has a higher priority *@return* /
    @Bean
    @ConditionalOnMissingBean(DiscoveryClientRouteLocator.class)
    public DiscoveryClientRouteLocator discoveryRouteLocator(a) {
        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(a) {
        return new ZuulDiscoveryRefreshListener();
    }

    @Bean
    @ConditionalOnMissingBean(ServiceRouteMapper.class)
    public ServiceRouteMapper serviceRouteMapper(a) {
        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());
            returnhelper; }}/** * Add 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(a) {
            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());
            returnhelper; }}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 instanceofHeartbeatEvent) { HeartbeatEvent e = (HeartbeatEvent) event; resetIfNeeded(e.getValue()); }}private void resetIfNeeded(Object value) {
            if (this.monitor.update(value)) { reset(); }}private void reset(a) {
            this.zuulHandlerMapping.setDirty(true); }}}Copy the code
  • ZuulServerAutoConfiguration and ZuulProxyAutoConfiguration which model to use, it is respectively by @ EnableZuulServer and @ EnableZuulProxy annotations to the difference
  • The former uses ZuulProperties for configuring routing addressing;
  • The Ribbon uses service discovery as routing addressing and load balancing for clients, which is the most commonly used.

Second, @ EnableZuulProxy

  • @ EnableZuulProxy annotations
/**
 * 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 {
}
Copy the code
  • @ EnableZuulProxy analysis
  • @enablecircuitbreaker Note used to enable the short-circuit breaker function
/**
 * 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 {

}
Copy the code
  • @Import(ZuulProxyMarkerConfiguration.class)
  • ZuulProxyMarkerConfiguration.Marker.class
@Configuration
public class ZuulProxyMarkerConfiguration {
    @Bean
    public Marker zuulProxyMarkerBean(a) {
        return new Marker();
    }

    class Marker {}}Copy the code

Use Consul as the registry

  • Zuul in @enableZuulProxy mode requires registry support as Eureka has been abandoned and I’m using Consul here

1. Add Maven dependencies

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

2. Add the @enableDiscoveryClient annotation to the startup class

@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class ZuulApplication {

    public static void main(String[] args) { SpringApplication.run(ZuulApplication.class, args); }}Copy the code

3. After all the above steps, the entire service Gateway Zuul application is ready to go

Four,

1.Spring Cloud makes encapsulation and integration of Netflix Zuul, making it more convenient to use Zuul in Spring Cloud environment. Simply add the Spring-cloud-starter-Zuul maven dependency and add @enableZuulProxy to the startup class to create a Zuul application. 2.Spring Cloud Zuul is actually adding some ZuulFilters on the basis of servlets to accomplish some additional things, which are packaged into a framework.