IT俱乐部 Java SpringCloud Gateway自动装配实现流程详解

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

启动依赖

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

org.springframework.cloudspring-cloud-starter-gateway

点进去之后找到它的依赖

  org.springframework.cloudspring-cloud-starter3.1.1compileorg.springframework.cloudspring-cloud-gateway-server3.1.1compileorg.springframework.bootspring-boot-starter-webflux2.6.3compileorg.springframework.cloudspring-cloud-starter-loadbalancer3.1.1compiletrue

从名称上可以判断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 {

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

public interface WebHandler {
	/**
	 * Handle the web server exchange.
	 * @param exchange the current server exchange
	 * @return {@code Mono} to indicate when request handling is complete
	 */
	Mono 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 {

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 propsProvider) {
			HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
			WebFluxProperties properties = propsProvider.getIfAvailable();
			if (properties != null && StringUtils.hasText(properties.getBasePath())) {
				Map 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 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 handlers) {
		super(delegate);
		List 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内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!

本文收集自网络,不代表IT俱乐部立场,转载请注明出处。https://www.2it.club/code/java/7273.html
上一篇
下一篇
联系我们

联系我们

在线咨询: QQ交谈

邮箱: 1120393934@qq.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部