前言

  • 由上一章节可以知道要创建一个zuul应用,只需添加spring-cloud-starter-zuul maven依赖及启动类上添加@EnableZuulProxy就可创建一个zuul应用,那么要知道Zuul工作原理就需从这个两个地方作为入口进行研究

  • zuul版本: 1.4.3.RELEASE

解析

Zuul 初始化

spring-cloud-starter-zuul starter
  • 我们先查看spring-cloud-starter-zuul starter包下有什么,这里的重点就是pom.xml文件,ZuulDeprecationWarningAutoConfiguration.java此类已经被@Deprecated
  • 打开org.springframework.cloud/spring-cloud-starter-zuul/pom.xml ,可以看到是依赖了spring-cloud-starter-netflix-zuul
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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>1.4.3.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
  • 这里关注spring-cloud-starter-netflix-zuul/pom.xmlspring-cloud-starter-netflix-zuul-1.4.3.RELEASE.jar!/META-INF/spring.provides

    • 打开/pom.xml可以看到依赖了com.netflix.zuul,所以说Spring Cloud Zuul是基于netflix公司的zuul实现的,除此之外还添加了hystrixribbon依赖,所以zuul是自带这两个功能的,spring-boot-starter-web依赖可以使应用成为web应用,spring-boot-starter-actuator是监控依赖

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      <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>1.4.3.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的一系列框架了,下面是代码框架图

  • 可以看到这个炸包也包含了spring.factories文件,所以SpringBoot项目启动的时候会检索此配置文件,此文件是zuul实现自动注册配置的关键,下面可以看到熟悉的zuul,hystrix,feign,ribbon的自动配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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功能最为完全
  • ZuulServerAutoConfigurationZuulProxyAutoConfiguration

    • ZuulServerAutoConfiguration自动配置类,启动类上如果有@EnableZuulServer则此类生效

      • 下面代码可以看到大量使用了@Conditional作为条件判断,注意这个ZuulController这个Bean,它是我们Zuul的请求入口,这个类实现了Controller了,说明这里也使用了Spring MVC DispatcherServlet
      • 同时此类注册了大量的ZuulFilter
      • 代码:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89
        90
        91
        92
        93
        94
        95
        96
        97
        98
        99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        150
        151
        152
        153
        154
        155
        156
        157
        158
        159
        160
        161
        162
        163
        164
        165
        166
        167
        168
        169
        170
        171
        172
        173
        174
        175
        176
        177
        178
        179
        180
        181
        182
        183
        184
        185
        186
        187
        188
        189
        190
        /**
        * @author Spencer Gibb
        * @author Dave Syer
        * @author Biju Kunjummen
        */
        @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的所有功能,并在此基础上添加了使用了服务发现作为路由寻址功能
      • 代码:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89
        90
        91
        92
        93
        94
        95
        96
        97
        98
        99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        150
        151
        152
        153
        154
        155
        156
        157
        158
        159
        160
        161
        162
        163
        164
        165
        166
        167
        168
        169
        170
        171
        172
        173
        174
        175
        176
        177
        178
        179
        180
        181
        182
        183
        184
        185
        186
        187
        188
        189
        190
        191
        192
        /**
        * @author Spencer Gibb
        * @author Dave Syer
        * @author Biju Kunjummen
        */
        @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);
        }

        }

        }
  • ZuulServerAutoConfigurationZuulProxyAutoConfiguration具体使用哪种模式,是分别通过@EnableZuulServer@EnableZuulProxy注解来区别的

    • 前者使用了ZuulProperties进行配置路由寻址;
    • 后者在原来的基础上添加了使用了服务发现作为路由寻址功能, 并使用Ribbon做客户端的负载均衡,这个最为常用;
@EnableZuulProxy
  • @EnableZuulProxy注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 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 Spencer Gibb
* @author Dave Syer
* @author Biju Kunjummen
*/
@EnableCircuitBreaker
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyMarkerConfiguration.class)
public @interface EnableZuulProxy {
}
  • @EnableZuulProxy分析

    • @EnableCircuitBreaker注解用于开启短路器功能

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      /**
      * Annotation to enable a CircuitBreaker implementation.
      * http://martinfowler.com/bliki/CircuitBreaker.html
      * @author Spencer Gibb
      */
      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      @Inherited
      @Import(EnableCircuitBreakerImportSelector.class)
      public @interface EnableCircuitBreaker {

      }
    • @Import(ZuulProxyMarkerConfiguration.class)注解用于注册ZuulProxyMarkerConfiguration.Marker.class这个Bean,这个Bean与上面的ZuulProxyAutoConfiguration的条件注解相对应@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class),所以说如果启动类带了这个@EnableZuulProxy注解将会开启ZuulProxyMarkerConfiguration自动注册的功能,Spring这个可配置化对使用者来说十分方便

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      @Configuration
      public class ZuulProxyMarkerConfiguration {
      @Bean
      public Marker zuulProxyMarkerBean() {
      return new Marker();
      }

      class Marker {
      }
      }
使用Consul作为注册中心
  • @EnableZuulProxy模式下的zuul需要注册中心的支持,因为eureka已经被抛弃了,我们这里选用的是Consul

    • 添加Maven依赖

      1
      2
      3
      4
      <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-consul-discovery</artifactId>
      </dependency>
    • 启动类上加上@EnableDiscoveryClient注解

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      @EnableZuulProxy
      @EnableDiscoveryClient
      @SpringBootApplication
      public class ZuulApplication {

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

      }
    • 这样Zuul应用就可以发挥作用了

      总结

  • 本章节对Zuul的初始化进行了一次梳理,可以发现Zuul的初始化就是注册各种需要的Bean,粮草备好之后就是要发挥作用了,下一章节将介绍其具体是怎样发挥作用的
  • Spring CloudNetflix Zuul做了封装集成, 使得在Spring Cloud环境中使用Zuul更方便,只需添加spring-cloud-starter-zuul maven依赖及启动类上添加@EnableZuulProxy就可创建一个zuul应用
  • Spring Cloud Zuul 实际上就是在Servlet的基础上添加了一些ZuulFilter去完成一些额外事情,封装了就成框架了

参考