<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring Cloud Gateway 源碼剖析之配置初始化

          共 20077字,需瀏覽 41分鐘

           ·

          2021-03-31 12:27

          點(diǎn)擊上方老周聊架構(gòu)關(guān)注我



          一、前言

          相信大多數(shù)公司都會(huì)有自己公司的專(zhuān)有網(wǎng)關(guān)服務(wù),雖說(shuō)是自研,但很少會(huì)有從零開(kāi)始開(kāi)發(fā)一個(gè)網(wǎng)關(guān)服務(wù),基本上是基于市面上比較流行的網(wǎng)關(guān)組件像 Zuul、Gateway、Soul 等進(jìn)行二次封裝的。那如果自己公司有相應(yīng)的網(wǎng)關(guān)業(yè)務(wù)需求的話(huà),這就要對(duì)網(wǎng)關(guān)產(chǎn)品的底層原理要比較熟悉了,這樣做起來(lái)也比較順手。本系列只針對(duì) Gateway 組件進(jìn)行源碼剖析,我在想第一篇如何說(shuō)會(huì)比較好,本來(lái)想直接說(shuō)核心流程的,想了想還是先從配置初始化說(shuō)起。話(huà)不多說(shuō),接下來(lái)我們就開(kāi)始 Spring Cloud Gateway 源碼剖析之旅吧。

          二、揭秘配置初始化

          那我們就從項(xiàng)目中 maven 依賴(lài)的 jar 包開(kāi)始吧。

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

          直接跟進(jìn)去發(fā)現(xiàn)有三個(gè)依賴(lài),憑借我們的開(kāi)發(fā)經(jīng)驗(yàn),盲猜一下 spring-cloud-gateway-core 就是 gateway 的核心依賴(lài)。

          直接找到對(duì)應(yīng)的 maven 依賴(lài)包:


          不知道大家有沒(méi)有什么疑問(wèn),找了這個(gè)包,然后 gateway 是怎么與 Spring Boot 項(xiàng)目相關(guān)聯(lián)的呢?

          相信有一定經(jīng)驗(yàn)的朋友知道 Spring Boot 啟動(dòng)的時(shí)候有個(gè) @SpringBootApplication 注解,而這個(gè)注解包含了一個(gè)非常重要的子注解 @EnableAutoConfiguration,該注解表示開(kāi)啟自動(dòng)配置功能,是 Spring Boot 框架最重要的注解,也是實(shí)現(xiàn)自動(dòng)化配置的注解。

          Spring Cloud Gateway 也是同樣的套路,那我們直接找到 /META-INF/spring.factories 文件,果不其然。

          // Auto Configure
          org.springframework.boot.autoconfigure.EnableAutoConfiguration=
          // 依賴(lài)包的校驗(yàn)配置
          org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,
          // 網(wǎng)關(guān)的核心配置
          org.springframework.cloud.gateway.config.GatewayAutoConfiguration,
          // 負(fù)載均衡相關(guān)依賴(lài)配置信息
          org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration,
          // 度量相關(guān)依賴(lài)配置信息
          org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,
          // 流控的依賴(lài)配置信息
          org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,
          // 注冊(cè)中心相關(guān)的依賴(lài)配置
          org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration

          分析上面的自動(dòng)配置之前,我們先來(lái)了解下 SpringBoot 常用注解的含義。

          // 執(zhí)行順序
          @AutoConfigureBefore:在指定的配置類(lèi)初始化前加載
          @AutoConfigureAfter:在指定的配置類(lèi)初始化后再加載
          @AutoConfigureOrder:數(shù)越小越先初始化
          // 條件配置
          @ConditionalOnClass :classpath中存在該類(lèi)時(shí)起效
          @ConditionalOnMissingClass :classpath中不存在該類(lèi)時(shí)起效
          @ConditionalOnBean :DI容器中存在該類(lèi)型Bean時(shí)起效
          @ConditionalOnMissingBean :DI容器中不存在該類(lèi)型Bean時(shí)起效
          @ConditionalOnSingleCandidate :DI容器中該類(lèi)型Bean只有一個(gè)或@Primary的只有一個(gè)時(shí)起效
          @ConditionalOnExpression :SpEL表達(dá)式結(jié)果為true時(shí)
          @ConditionalOnProperty :參數(shù)設(shè)置或者值一致時(shí)起效
          @ConditionalOnResource :指定的文件存在時(shí)起效
          @ConditionalOnJndi :指定的JNDI存在時(shí)起效
          @ConditionalOnJava :指定的Java版本存在時(shí)起效
          @ConditionalOnWebApplication :Web應(yīng)用環(huán)境下起效
          @ConditionalOnNotWebApplication :非Web應(yīng)用環(huán)境下起效

          1、GatewayClassPathWarningAutoConfiguration

          GatewayClassPathWarningAutoConfiguration 用于檢查項(xiàng)目是否正確導(dǎo)入 spring-boot-starter-webflux 依賴(lài),而不是錯(cuò)誤導(dǎo)入 spring-boot-starter-web 依賴(lài),同時(shí) GatewayClassPathWarningAutoConfiguration 在 EnableAutoConfiguration 配置加載前加載。

          @Configuration
          // 執(zhí)行順序注解
          // 當(dāng)前注解標(biāo)識(shí)需要在GatewayAutoConfiguration前加載此配置
          @AutoConfigureBefore({GatewayAutoConfiguration.class})
          public class GatewayClassPathWarningAutoConfiguration {
              private static final Log log = LogFactory.getLog(GatewayClassPathWarningAutoConfiguration.class);
              private static final String BORDER = "\n\n**********************************************************\n\n";

              public GatewayClassPathWarningAutoConfiguration() {
              }

              @Configuration
              // 條件判斷注解
              // classpath中不存在org.springframework.web.reactive.DispatcherHandler時(shí)起效,標(biāo)識(shí)項(xiàng)目未導(dǎo)入了spring-boot-starter-webflux包
              @ConditionalOnMissingClass({"org.springframework.web.reactive.DispatcherHandler"})
              protected static class WebfluxMissingFromClasspathConfiguration {
                  public WebfluxMissingFromClasspathConfiguration() {
                      // 當(dāng)前項(xiàng)目未導(dǎo)入了spring-boot-starter-webflux依賴(lài)時(shí),打印警告日志
                      GatewayClassPathWarningAutoConfiguration.log.warn("\n\n**********************************************************\n\nSpring Webflux is missing from the classpath, which is required for Spring Cloud Gateway at this time. Please add spring-boot-starter-webflux dependency.\n\n**********************************************************\n\n");
                  }
              }

              @Configuration
              // 條件判斷注解
              // classpath中存在org.springframework.web.servlet.DispatcherServlet時(shí)起效,標(biāo)識(shí)項(xiàng)目導(dǎo)入了spring-boot-starter-web包
              @ConditionalOnClass(
                  name = {"org.springframework.web.servlet.DispatcherServlet"}
              )
              protected static class SpringMvcFoundOnClasspathConfiguration {
                  public SpringMvcFoundOnClasspathConfiguration() {
                      // 當(dāng)前項(xiàng)目導(dǎo)入了spring-boot-starter-web依賴(lài)時(shí),打印警告日志
                      GatewayClassPathWarningAutoConfiguration.log.warn("\n\n**********************************************************\n\nSpring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. Please remove spring-boot-starter-web dependency.\n\n**********************************************************\n\n");
                  }
              }
          }


          2、GatewayAutoConfiguration

          GatewayAutoConfiguration 是 Spring Cloud Gateway 核心配置類(lèi),這里只列幾個(gè)核心的,初始化如下 :

          • RoutePredicateHandlerMapping:查找匹配到 Route 并進(jìn)行處理

          • GatewayProperties:加載網(wǎng)關(guān)配置

          • RouteDefinitionRouteLocator:創(chuàng)建一個(gè)根據(jù) RouteDefinition 轉(zhuǎn)換的路由定位器

          • GatewayWebfluxEndpoint:管理網(wǎng)關(guān)的 HTTP API


          @Configuration
          // 條件注解
          // 通過(guò) spring.cloud.gateway.enabled 配置網(wǎng)關(guān)的開(kāi)啟與關(guān)閉
          // matchIfMissing = true => 網(wǎng)關(guān)默認(rèn)開(kāi)啟。
          @ConditionalOnProperty(
              name = {"spring.cloud.gateway.enabled"},
              matchIfMissing = true
          )
          @EnableConfigurationProperties
          @AutoConfigureBefore({HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class})
          @AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
          @ConditionalOnClass({DispatcherHandler.class})
          public class GatewayAutoConfiguration {
              public GatewayAutoConfiguration() {
              }

              @Bean
              public StringToZonedDateTimeConverter stringToZonedDateTimeConverter() {
                  return new StringToZonedDateTimeConverter();
              }

              @Bean
              public RouteLocatorBuilder routeLocatorBuilder(ConfigurableApplicationContext context) {
                  return new RouteLocatorBuilder(context);
              }

              @Bean
              @ConditionalOnMissingBean
              public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
                  return new PropertiesRouteDefinitionLocator(properties);
              }

              @Bean
              @ConditionalOnMissingBean({RouteDefinitionRepository.class})
              public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
                  return new InMemoryRouteDefinitionRepository();
              }

              @Bean
              @Primary
              public RouteDefinitionLocator routeDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators) {
                  return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
              }

              @Bean
              public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, List<GatewayFilterFactory> GatewayFilters, List<RoutePredicateFactory> predicates, RouteDefinitionLocator routeDefinitionLocator, @Qualifier("webFluxConversionService") ConversionService conversionService) {
                  return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties, conversionService);
              }

              @Bean
              @Primary
              public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
                  return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
              }

              @Bean
              public RouteRefreshListener routeRefreshListener(ApplicationEventPublisher publisher) {
                  return new RouteRefreshListener(publisher);
              }

              @Bean
              public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
                  return new FilteringWebHandler(globalFilters);
              }

              @Bean
              public GlobalCorsProperties globalCorsProperties() {
                  return new GlobalCorsProperties();
              }

              @Bean
              public RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties, Environment environment) {
                  return new RoutePredicateHandlerMapping(webHandler, routeLocator, globalCorsProperties, environment);
              }

              @Bean
              public GatewayProperties gatewayProperties() {
                  return new GatewayProperties();
              }
              ...
          }


          3、GatewayLoadBalancerClientAutoConfiguration

          GatewayLoadBalancerClientAutoConfiguration 作用是初始化 LoadBalancerClientFilter 路由的負(fù)載均衡攔截器

          @Configuration
          // 條件判斷注解
          // classpath中存在LoadBalancerClient和RibbonAutoConfiguration和DispatcherHandler時(shí)此配置起效
          @ConditionalOnClass({LoadBalancerClient.class, RibbonAutoConfiguration.class, DispatcherHandler.class})
          // 執(zhí)行順序注解
          @AutoConfigureAfter({RibbonAutoConfiguration.class})
          @EnableConfigurationProperties({LoadBalancerProperties.class})
          public class GatewayLoadBalancerClientAutoConfiguration {
              public GatewayLoadBalancerClientAutoConfiguration() {
              }

              @Bean
              // 條件判斷注解
              // DI容器中存在LoadBalancerClient類(lèi)型Bean時(shí)起效
              @ConditionalOnBean({LoadBalancerClient.class})
              @ConditionalOnMissingBean({LoadBalancerClientFilter.class})
              public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client, LoadBalancerProperties properties) {
                  return new LoadBalancerClientFilter(client, properties);
              }
          }

          4、GatewayMetricsAutoConfiguration

          GatewayMetricsAutoConfiguration 作用是初始化 GatewayMetricsFilter 路由的度量攔截器

          @Configuration
          @ConditionalOnProperty(
              name = {"spring.cloud.gateway.enabled"},
              matchIfMissing = true
          )
          @AutoConfigureBefore({HttpHandlerAutoConfiguration.class})
          @AutoConfigureAfter({MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class})
          @ConditionalOnClass({DispatcherHandler.class, MeterRegistry.class, MetricsAutoConfiguration.class})
          public class GatewayMetricsAutoConfiguration {
              public GatewayMetricsAutoConfiguration() {
              }

              @Bean
              @ConditionalOnBean({MeterRegistry.class})
              @ConditionalOnProperty(
                  name = {"spring.cloud.gateway.metrics.enabled"},
                  matchIfMissing = true
              )
              public GatewayMetricsFilter gatewayMetricFilter(MeterRegistry meterRegistry) {
                  return new GatewayMetricsFilter(meterRegistry);
              }
          }

          5、GatewayRedisAutoConfiguration

          GatewayRedisAutoConfiguration 配置作用是初始化初始化 RedisRateLimiter 限流功能的,RequestRateLimiterGatewayFilterFactory 基于 RedisRateLimiter 實(shí)現(xiàn)網(wǎng)關(guān)的限流功能。

          @Configuration
          @AutoConfigureAfter({RedisReactiveAutoConfiguration.class})
          @AutoConfigureBefore({GatewayAutoConfiguration.class})
          @ConditionalOnBean({ReactiveRedisTemplate.class})
          @ConditionalOnClass({RedisTemplate.class, DispatcherHandler.class})
          class GatewayRedisAutoConfiguration {
              GatewayRedisAutoConfiguration() {
              }

              @Bean
              public RedisScript redisRequestRateLimiterScript() {
                  DefaultRedisScript redisScript = new DefaultRedisScript();
                  redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("META-INF/scripts/request_rate_limiter.lua")));
                  redisScript.setResultType(List.class);
                  return redisScript;
              }

              @Bean
              public ReactiveRedisTemplate<String, String> stringReactiveRedisTemplate(ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {
                  RedisSerializer<String> serializer = new StringRedisSerializer();
                  RedisSerializationContext<String, String> serializationContext = RedisSerializationContext.newSerializationContext().key(serializer).value(serializer).hashKey(serializer).hashValue(serializer).build();
                  return new ReactiveRedisTemplate(reactiveRedisConnectionFactory, serializationContext);
              }

              @Bean
              @ConditionalOnMissingBean
              public RedisRateLimiter redisRateLimiter(ReactiveRedisTemplate<String, String> redisTemplate, @Qualifier("redisRequestRateLimiterScript") RedisScript<List<Long>> redisScript, Validator validator) {
                  return new RedisRateLimiter(redisTemplate, redisScript, validator);
              }
          }

          6、GatewayDiscoveryClientAutoConfiguration

          GatewayDiscoveryClientAutoConfiguration 的作用是初始化配置路由中的注冊(cè)發(fā)現(xiàn)服務(wù)信息

          @Configuration
          // 同2
          @ConditionalOnProperty(
              name = {"spring.cloud.gateway.enabled"},
              matchIfMissing = true
          )
          @AutoConfigureBefore({GatewayAutoConfiguration.class})
          @AutoConfigureAfter({CompositeDiscoveryClientAutoConfiguration.class})
          @ConditionalOnClass({DispatcherHandler.class, DiscoveryClient.class})
          @EnableConfigurationProperties
          public class GatewayDiscoveryClientAutoConfiguration {
              public GatewayDiscoveryClientAutoConfiguration() {
              }

              @Bean
              // 當(dāng)classpath中存在DiscoveryClient起效
              @ConditionalOnBean({DiscoveryClient.class})
              // 通過(guò)spring.cloud.gateway.discovery.locator.enabled配置注冊(cè)中心查找的開(kāi)啟與關(guān)閉
              @ConditionalOnProperty(
                  name = {"spring.cloud.gateway.discovery.locator.enabled"}
              )
              public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
                  return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
              }

              @Bean
              public DiscoveryLocatorProperties discoveryLocatorProperties() {
                  DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
                  properties.setPredicates(initPredicates());
                  properties.setFilters(initFilters());
                  return properties;
              }

              public static List<PredicateDefinition> initPredicates() {
                  ArrayList<PredicateDefinition> definitions = new ArrayList();
                  PredicateDefinition predicate = new PredicateDefinition();
                  predicate.setName(NameUtils.normalizeRoutePredicateName(PathRoutePredicateFactory.class));
                  predicate.addArg("pattern""'/'+serviceId+'/**'");
                  definitions.add(predicate);
                  return definitions;
              }

              public static List<FilterDefinition> initFilters() {
                  ArrayList<FilterDefinition> definitions = new ArrayList();
                  FilterDefinition filter = new FilterDefinition();
                  filter.setName(NameUtils.normalizeFilterFactoryName(RewritePathGatewayFilterFactory.class));
                  String regex = "'/' + serviceId + '/(?<remaining>.*)'";
                  String replacement = "'/${remaining}'";
                  filter.addArg("regexp", regex);
                  filter.addArg("replacement", replacement);
                  definitions.add(filter);
                  return definitions;
              }
          }

          三、總結(jié)

          通過(guò)自動(dòng)加載初始化上述六個(gè)配置實(shí)例,Spring Cloud Gateway 就完成自身的加載和初始化工作。跟著老周下來(lái)應(yīng)該還算清晰吧,下一篇我們來(lái)說(shuō)一下 Route 數(shù)據(jù)模型,敬請(qǐng)期待~



          歡迎大家關(guān)注我的公眾號(hào)【老周聊架構(gòu)】,Java后端主流技術(shù)棧的原理、源碼分析、架構(gòu)以及各種互聯(lián)網(wǎng)高并發(fā)、高性能、高可用的解決方案。

          喜歡的話(huà),點(diǎn)贊、再看、分享三連。

          點(diǎn)個(gè)在看你最好看



          瀏覽 43
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  先锋资源成人 | а√天堂中文在线资源8 | 欧美成人大香蕉 | 日本午夜福利中文字幕 | 日韩中文字幕视频 |