SpringCloud Gateway自动装配实现流程详解

 更新时间:2022年10月21日 10:59:30   作者:Polarisy丶  
Spring Cloud Gateway旨在为微服务架构提供一种简单有效的、统一的 API 路由管理方式。Spring Cloud Gateway 作为 Spring Cloud 生态系中的网关,它不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全、监控/埋点和限流等

启动依赖

找到gateway的依赖,spring-cloud-starter-gateway

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

点进去之后找到它的依赖

  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter</artifactId>
      <version>3.1.1</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-gateway-server</artifactId>
      <version>3.1.1</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
      <version>2.6.3</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-loadbalancer</artifactId>
      <version>3.1.1</version>
      <scope>compile</scope>
      <optional>true</optional>
    </dependency>
  </dependencies>

从名称上可以判断spring-cloud-gateway-server是gateway的核心依赖,找到依赖包,看到如下结构

spring.factories是一些自动装配的类,如下可以看到

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayResilience4JCircuitBreakerAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayNoLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,\
org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration,\
org.springframework.cloud.gateway.config.SimpleUrlHandlerMappingGlobalCorsAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayReactiveOAuth2AutoConfiguration

org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.gateway.config.GatewayEnvironmentPostProcessor

# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.cloud.gateway.support.MvcFoundOnClasspathFailureAnalyzer

其中比较重要的是GatewayAutoConfiguration,负责很多bean的初始化,类声明如下:

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore({ HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class })
@AutoConfigureAfter({ GatewayReactiveLoadBalancerClientAutoConfiguration.class,
		GatewayClassPathWarningAutoConfiguration.class })
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {			

@AutoConfigureBefore@AutoConfigureAfter分别是在之前和之后加载

其中HttpHandlerAutoConfigurationWebFluxAutoConfiguration算是比较重要的装配类

WebFluxAutoConfiguration

先看WebFluxAutoConfiguration,类声明如下:

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })
@AutoConfigureAfter({ ReactiveWebServerFactoryAutoConfiguration.class, CodecsAutoConfiguration.class,
		ReactiveMultipartAutoConfiguration.class, ValidationAutoConfiguration.class,
		WebSessionIdResolverAutoConfiguration.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class WebFluxAutoConfiguration {

其中部分代码如下:

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ WebProperties.class, WebFluxProperties.class })
@Import({ EnableWebFluxConfiguration.class })
@Order(0)
public static class WebFluxConfig implements WebFluxConfigurer {

可以看到通过WebFluxAutoConfiguration 通过 WebFluxConfig 导入了 EnableWebFluxConfiguration

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ WebProperties.class, ServerProperties.class })
public static class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration {

EnableWebFluxConfiguration继承于DelegatingWebFluxConfiguration

@Configuration(proxyBeanMethods = false)
public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport {

DelegatingWebFluxConfiguration又继承于WebFluxConfigurationSupport

在WebFluxConfigurationSupport中可以看到很熟悉的东西

@Bean
public DispatcherHandler webHandler() {
    //BeanName为webHandler
	return new DispatcherHandler();
}

有点联想到DispatcherSerlvet,类似前端控制器

public class DispatcherHandler implements WebHandler, PreFlightRequestHandler, ApplicationContextAware {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->

可以看到DispatcherHandler实现了WebHandler接口并实现了其中的handle方法

public interface WebHandler {
	/**
	 * Handle the web server exchange.
	 * @param exchange the current server exchange
	 * @return {@code Mono<Void>} to indicate when request handling is complete
	 */
	Mono<Void> handle(ServerWebExchange exchange);
}

可以猜到handle应该就是核心的处理方法,此时又有疑问,该方法什么时候被调用,被谁调用的

官方文档上提到WebHandler 上面还有一个关键的 API HttpHandler

For server request processing there are two levels of support.

HttpHandler: Basic contract for HTTP request handling with non-blocking I/O and Reactive Streams back pressure, along with adapters for Reactor Netty, Undertow, Tomcat, Jetty, and any Servlet 3.1+ container.

WebHandler API: Slightly higher level, general-purpose web API for request handling, on top of which concrete programming models such as annotated controllers and functional endpoints are built.

从上面的英文可以看到 HttpHandler 是比 WebHandler 更加底层的一个 API,也就是说很可能是由 HttpHandler 来调用 WebHandler (请求由下往上),那DispatcherHandler作为 WebHandler 的一个实现,也很有可能会被HttpHandler的具体实现所持有。

通过HttpHandler的实现类不难找到HttpWebHandlerAdapter 就是我们要找的,并且持有一个WebHandher 对象,当然也可以通过断点调试找到。

public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHandler {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->

HttpWebHandlerAdapter继承于WebHandlerDecorator

public class WebHandlerDecorator implements WebHandler {
	private final WebHandler delegate;
	/**
	 * Return the wrapped delegate.
	 */
	public WebHandler getDelegate() {
		return this.delegate;
	}

可以看到WebHandlerDecorator持有WebHandler对象

总之,我们找到了调用 DispatcherHandher 的地方了,那下一步我们要找 HttpWebHandlerAdapter 是在哪里被装配的,并且webHandler 是是什么时候被注入的,注入的 webHandler 是否就是 DispatcherHandler?

HttpHandlerAutoConfiguration

前面说过的另外一个装配类HttpHandlerAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DispatcherHandler.class, HttpHandler.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnMissingBean(HttpHandler.class)
@AutoConfigureAfter({ WebFluxAutoConfiguration.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class HttpHandlerAutoConfiguration {
	@Configuration(proxyBeanMethods = false)
	public static class AnnotationConfig {
		private final ApplicationContext applicationContext;
		public AnnotationConfig(ApplicationContext applicationContext) {
			this.applicationContext = applicationContext;
		}
		@Bean
		public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
			HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
			WebFluxProperties properties = propsProvider.getIfAvailable();
			if (properties != null && StringUtils.hasText(properties.getBasePath())) {
				Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
				return new ContextPathCompositeHandler(handlersMap);
			}
			return httpHandler;
		}
	}
}

可以看到这里注入了一个HttpHandler对象,难道就是HttpWebHandlerAdapter ,继续往下看

首先调用了WebHttpHandlerBuilder.applicationContext(this.applicationContext)方法,点进去看

	public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
		WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
				context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class), context);
	    ......
		return builder;		

可以看到通过context上下文对象通过beanName获取bean来作为参数初始化WebHttpHandlerBuilder对象

/** Well-known name for the target WebHandler in the bean factory. */
public static final String WEB_HANDLER_BEAN_NAME = "webHandler";

而这个beanName正式前面说过的DispatcherHandler对象

	private WebHttpHandlerBuilder(WebHandler webHandler, @Nullable ApplicationContext applicationContext) {
		Assert.notNull(webHandler, "WebHandler must not be null");
		this.webHandler = webHandler;
		this.applicationContext = applicationContext;
	}

WebHttpHandlerBuilder中的webHandler属性赋值为DispatcherHandler对象

接着进入build()方法,整体可以看到返回的HttpHandler对象就是HttpWebHandlerAdapter

	public HttpHandler build() {
		WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
		decorated = new ExceptionHandlingWebHandler(decorated,  this.exceptionHandlers);
		HttpWebHandlerAdapter adapted = new HttpWebHandlerAdapter(decorated);
		if (this.sessionManager != null) {
			adapted.setSessionManager(this.sessionManager);
		}
		if (this.codecConfigurer != null) {
			adapted.setCodecConfigurer(this.codecConfigurer);
		}
		if (this.localeContextResolver != null) {
			adapted.setLocaleContextResolver(this.localeContextResolver);
		}
		if (this.forwardedHeaderTransformer != null) {
			adapted.setForwardedHeaderTransformer(this.forwardedHeaderTransformer);
		}
		if (this.applicationContext != null) {
			adapted.setApplicationContext(this.applicationContext);
		}
		adapted.afterPropertiesSet();
		return (this.httpHandlerDecorator != null ? this.httpHandlerDecorator.apply(adapted) : adapted);
	}

首先看第一行

//这里的webHandler就是DispatcherHandler对象
WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
	public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
		super(handler);
		this.chain = new DefaultWebFilterChain(handler, filters);
	}

调用父类的构造方法

private final WebHandler delegate;	
public WebHandlerDecorator(WebHandler delegate) {
		Assert.notNull(delegate, "'delegate' must not be null");
		this.delegate = delegate;
	}

此时将delegate赋值为DispatcherHandler对象

接着第二行

//此时入参中的decorated是FilteringWebHandler对象
decorated = new ExceptionHandlingWebHandler(decorated,  this.exceptionHandlers);
	public ExceptionHandlingWebHandler(WebHandler delegate, List<WebExceptionHandler> handlers) {
		super(delegate);
		List<WebExceptionHandler> handlersToUse = new ArrayList<>();
		handlersToUse.add(new CheckpointInsertingHandler());
		handlersToUse.addAll(handlers);
		this.exceptionHandlers = Collections.unmodifiableList(handlersToUse);
	}

再次调用父类的构造方法将此对象的父类中delegate属性赋值为FilteringWebHandler对象

接着第三行

HttpWebHandlerAdapter adapted = new HttpWebHandlerAdapter(decorated);
	public HttpWebHandlerAdapter(WebHandler delegate) {
		super(delegate);
	}

一样的道理将父类中delegate属性赋值为ExceptionHandlingWebHandler对象

总结一下

HttpWebHandlerAdapter中delegate保存的是ExceptionHandlingWebHandler

ExceptionHandlingWebHandler中的delegate保存的是FilteringWebHandler

FilteringWebHandler中的delegate保存的是DispatcherHandler

到此这篇关于SpringCloud Gateway自动装配实现流程详解的文章就介绍到这了,更多相关SpringCloud Gateway内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java 静态链表实现示例详解

    java 静态链表实现示例详解

    这篇文章主要为大家介绍了java 静态链表实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • Java Socket实现单线程通信的方法示例

    Java Socket实现单线程通信的方法示例

    这篇文章主要介绍了Java Socket实现单线程通信的方法,结合具体实例形式分析了java socket单线程通信的原理与客户端、服务器端相关实现技巧,需要的朋友可以参考下
    2017-06-06
  • Java8 Collectors求和功能的自定义扩展操作

    Java8 Collectors求和功能的自定义扩展操作

    这篇文章主要介绍了Java8 Collectors求和功能的自定义扩展操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • Android读取本地或网络图片并转换为Bitmap

    Android读取本地或网络图片并转换为Bitmap

    这篇文章主要为大家详细介绍了Android读取本地或网络图片,并转换为Bitmap,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • 浅谈一下Spring中的createBean

    浅谈一下Spring中的createBean

    createBean是创建Bean的主要方法, 该方法位于:AbstractBeanFactory的doGetBean方法中的createBean调用。本文就来浅谈一下Spring中的createBean ,感兴趣的可以了解一下
    2022-07-07
  • 在Spring Boot中处理文件上传功能实现

    在Spring Boot中处理文件上传功能实现

    这篇文章主要介绍了如何在Spring Boot中处理文件上传,通过配置文件上传属性、创建控制器来处理上传的文件,并通过异常处理器来管理错误情况,可以快速实现文件上传功能,需要的朋友可以参考下
    2024-06-06
  • SpringBoot+WebSocket实现IM及时通讯的代码示例

    SpringBoot+WebSocket实现IM及时通讯的代码示例

    项目中碰到需要及时通讯的场景,使用springboot集成websocket,即可实现简单的及时通讯,本文介绍springboot如何集成websocket、IM及时通讯需要哪些模块、开发和部署过程中遇到的问题、以及实现小型IM及时通讯的代码,需要的朋友可以参考下
    2023-10-10
  • 如何利用Spring Boot 监控 SQL 运行情况

    如何利用Spring Boot 监控 SQL 运行情况

    这篇文章主要介绍了如何利用Spring Boot监控SQL运行情况,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-07-07
  • GitLab在IDEA中回滚主分支问题

    GitLab在IDEA中回滚主分支问题

    这是工作中遇到的问题,记录下来,也方便自己后面查看操作步骤,也方便各位遇到这个问题,不至于卡太久,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Spring事件监听详解

    Spring事件监听详解

    这篇文章主要介绍了Spring事件监听详解,文中有非常详细的图文解说及代码示例,对正在学习java Spring的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-05-05

最新评论