您现在的位置是:首页 >其他 >SpringCloud源码解析-gateway&openFeign网站首页其他

SpringCloud源码解析-gateway&openFeign

Allen-xs 2024-09-26 00:01:02
简介SpringCloud源码解析-gateway&openFeign

1. gateway 源码解析

1.1 自动装配

springcloud是基于springboot的,gateway各个组件的初始化入口在自动装配
在这里插入图片描述

1.2 核心装配

1.2.1 GatewayClassPathWarningAutoConfiguration

主要作用是校验依赖 在GatewayAutoConfiguration之前被加载

校验是否导入了spring-boot-starter-web, gateway非web容器,不需要导入 spring-boot-starter-web
校验是否缺少spring-boot-starter-webflux依赖, DispatcherHandler是gateway接收请求的入口组件

@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
public class GatewayClassPathWarningAutoConfiguration {

	private static final Log log = LogFactory
			.getLog(GatewayClassPathWarningAutoConfiguration.class);

	private static final String BORDER = "

**********************************************************

";


	/**
	 * 非web容器,不需要导入 spring-boot-starter-web
	 */
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")
	protected static class SpringMvcFoundOnClasspathConfiguration {

		public SpringMvcFoundOnClasspathConfiguration() {
			log.warn(BORDER
					+ "Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. "
					+ "Please remove spring-boot-starter-web dependency." + BORDER);
		}

	}

	/**
	 * 判断是否缺少  spring-boot-starter-webflux 依赖
	 */
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.springframework.web.reactive.DispatcherHandler")
	protected static class WebfluxMissingFromClasspathConfiguration {

		public WebfluxMissingFromClasspathConfiguration() {
			log.warn(BORDER + "Spring Webflux is missing from the classpath, "
					+ "which is required for Spring Cloud Gateway at this time. "
					+ "Please add spring-boot-starter-webflux dependency." + BORDER);
		}

	}

}

1.2.2 GatewayAutoConfiguration

  1. 网关的开启与关闭
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
  1. 初始化 NettyConfiguration
/**
 * 初始化 NettyConfiguration
 */

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HttpClient.class)
protected static class NettyConfiguration {
	...
}
  1. 初始化 GlobalFilter
	// GlobalFilter beans  初始化各种内置的  GlobalFilter

	@Bean
	public AdaptCachedBodyGlobalFilter adaptCachedBodyGlobalFilter() {
		return new AdaptCachedBodyGlobalFilter();
	}
  1. 初始化 FilteringWebHandler
@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
	return new FilteringWebHandler(globalFilters);
}
  1. 初始化 GatewayProperties
  2. 初始化 PrefixPathGatewayFilterFactory
  3. 初始化 RoutePredicateFactory
  4. 初始化 RouteDefinitionLocator
  5. 初始化 RouteLocator
  6. 初始化 RoutePredicateHandlerMapping
  7. 初始化 RoutePredicateHandlerMapping
    以上是核心组件GatewayAutoConfiguration的内容, 部分就不介绍了, 都是一些初始化的工作

1.2.3 GatewayLoadBalancerClientAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({LoadBalancerClient.class, RibbonAutoConfiguration.class, DispatcherHandler.class})
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@EnableConfigurationProperties(LoadBalancerProperties.class)
public class GatewayLoadBalancerClientAutoConfiguration {

	@Bean
	@ConditionalOnBean(LoadBalancerClient.class)
	@ConditionalOnMissingBean({LoadBalancerClientFilter.class, ReactiveLoadBalancerClientFilter.class})
	public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client,
															 LoadBalancerProperties properties) {
		return new LoadBalancerClientFilter(client, properties);
	}

}

内容比较简单, 初始化负载均衡过滤器, 在RibbonAutoConfiguration在后加载

1.2.4 GatewayRedisAutoConfiguration

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

	@Bean
	@SuppressWarnings("unchecked")
	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
	@ConditionalOnMissingBean
	public RedisRateLimiter redisRateLimiter(ReactiveStringRedisTemplate redisTemplate,
			@Qualifier(RedisRateLimiter.REDIS_SCRIPT_NAME) RedisScript<List<Long>> redisScript,
			ConfigurationService configurationService) {
		return new RedisRateLimiter(redisTemplate, redisScript, configurationService);
	}

}

Redis整合Lua脚本实现网管的限流

1.3 Gateway 工作机制

在这里插入图片描述

  1. Gateway 接收客户端请求
  2. 客户端请求与路由信息进行匹配,匹配成功的才能够被路由转发到相应的下游服务
  3. 请求经过 Filter 过滤器链,执行 pre 处理逻辑,如修改请求头信息等
  4. 请求被转发至下游服务并返回响应
  5. 响应经过 Filter 过滤器链,执行 post 处理逻辑
  6. 向客户端响应应答

1.3.1 Gateway的三个核心组件

Route(路由) RoutePredicate(路由断言) GatewayFilter(过滤器)

在这里插入图片描述

1.3.2 请求处理流程(图)

在这里插入图片描述

1.3.3 入口&流程

入口:spring-web:ReactorHttpHandlerAdapter.apply()

public class ReactorHttpHandlerAdapter implements BiFunction<HttpServerRequest, HttpServerResponse, Mono<Void>> {

	private static final Log logger = HttpLogging.forLogName(ReactorHttpHandlerAdapter.class);


	private final HttpHandler httpHandler;


	public ReactorHttpHandlerAdapter(HttpHandler httpHandler) {
		Assert.notNull(httpHandler, "HttpHandler must not be null");
		this.httpHandler = httpHandler;
	}


	@Override
	public Mono<Void> apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {
		NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());
		try {
			ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
			ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);

			if (request.getMethod() == HttpMethod.HEAD) {
				response = new HttpHeadResponseDecorator(response);
			}

			return this.httpHandler.handle(request, response)
					.doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))
					.doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));
		}
		catch (URISyntaxException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to get request URI: " + ex.getMessage());
			}
			reactorResponse.status(HttpResponseStatus.BAD_REQUEST);
			return Mono.empty();
		}
	}

}

对原始HttpServerRequest 和HttpServerResponse 进行封装, 交由HttpWebHandlerAdapter进行处理, 如下

@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
	if (this.forwardedHeaderTransformer != null) {
		request = this.forwardedHeaderTransformer.apply(request);
	}
	ServerWebExchange exchange = createExchange(request, response);

	LogFormatUtils.traceDebug(logger, traceOn ->
			exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
					(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));

	return getDelegate().handle(exchange)
			.doOnSuccess(aVoid -> logResponse(exchange))
			.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
			.then(Mono.defer(response::setComplete));
}

ServerWebExchange web上下文对象, 贯穿整个请求; getDelegate()获取的是ExceptionHandlingWebHandler(全局异常处理器)
最终交由DispatcherHandler.handle进行处理, 参考**请求处理流程(图)**的第一个缓解, 该包是spring-webflux下的

public class DispatcherHandler implements WebHandler, ApplicationContextAware {
	...
	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
		return Flux.fromIterable(this.handlerMappings)
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(createNotFoundError())
				.flatMap(handler -> invokeHandler(exchange, handler))
				.flatMap(result -> handleResult(exchange, result));
	}
	...
}

this.handlerMappings加载所有的处理器mapping, 通过mapping(最终获取的是路由断言的mapping)获取handler
在这里插入图片描述
RoutePredicateHandlerMapping.getHandler 在父类AbstractHandlerMapping#getHandler
继续查看RoutePredicateHandlerMapping.getHandler—>getHandlerInternal

protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
	// don't handle requests on management port if set and different than server port
	if (this.managementPortType == DIFFERENT && this.managementPort != null
			&& exchange.getRequest().getURI().getPort() == this.managementPort) {
		return Mono.empty();
	}
	exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());

	return lookupRoute(exchange) // 查找route
			// .log("route-predicate-handler-mapping", Level.FINER) //name this
			.flatMap((Function<Route, Mono<?>>) r -> {
				exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
				if (logger.isDebugEnabled()) {
					logger.debug(
							"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
				}

				exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
				return Mono.just(webHandler);
			}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
				exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
				if (logger.isTraceEnabled()) {
					logger.trace("No RouteDefinition found for ["
							+ getExchangeDesc(exchange) + "]");
				}
			})));
}

RoutePredicateHandlerMapping.lookupRoute获取路由信息, 也就是配置文件里面routes下面配置的路由
getPredicate().apply(exchange)路由断言对路由进行过滤

	protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
		// 拿到所有的route
		return this.routeLocator.getRoutes()
				// 单独过滤路由,这样filterWhen错误延迟就不是问题
				.concatMap(route -> Mono.just(route).filterWhen(r -> {
					// add the current route we are testing
					exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
					// 进行路由断言 Predicate
					return r.getPredicate().apply(exchange);
				})...

		/*
		 * TODO: trace logging if (logger.isTraceEnabled()) {
		 * logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
		 */
	}

gateway:AbstractHandlerMapping#getHandler 获得handler之后(最终获得的handler是FilteringWebHandler,里面包含了globalFilters)

然后执行handler, 处理结果, 主要含执行hander部分, DispatcherHandler中的invokeHandler() 方法

private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
	if (this.handlerAdapters != null) {
		for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
			if (handlerAdapter.supports(handler)) {
				return handlerAdapter.handle(exchange, handler);
			}
		}
	}
	return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}

继续往下走, SimpleHandlerAdapter执行handle, 传入上下文(exchange)以及FilteringWebHandler, 方法内部比较简单, 继续调用FilteringWebHandler的handle方法,

public class SimpleHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
		return WebHandler.class.isAssignableFrom(handler.getClass());
	}

	@Override
	public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
		WebHandler webHandler = (WebHandler) handler;
		Mono<Void> mono = webHandler.handle(exchange);
		return mono.then(Mono.empty());
	}

}
public class FilteringWebHandler implements WebHandler {
	...
	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
		List<GatewayFilter> gatewayFilters = route.getFilters();
		List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
		combined.addAll(gatewayFilters);
		// TODO: needed or cached?
		AnnotationAwareOrderComparator.sort(combined);
		if (logger.isDebugEnabled()) {
			logger.debug("Sorted gatewayFilterFactories: " + combined);
		}
		// 创建过滤器链并执行过滤器
		return new DefaultGatewayFilterChain(combined).filter(exchange);
	}
	...
}

以上可以看出将普通过滤器和全局过滤器进行合并成过滤器链, 然后执行过滤器
接下来看FilteringWebHandler.DefaultGatewayFilterChain(内部类)#filter方法, 执行过滤器

	private static class DefaultGatewayFilterChain implements GatewayFilterChain {

		private final int index;
		// 整合过后的所有过滤器
		private final List<GatewayFilter> filters;

		DefaultGatewayFilterChain(List<GatewayFilter> filters) {
			this.filters = filters;
			this.index = 0;
		}

		private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
			this.filters = parent.getFilters();
			this.index = index;
		}

		public List<GatewayFilter> getFilters() {
			return filters;
		}
		
		// 执行过滤器
		@Override
		public Mono<Void> filter(ServerWebExchange exchange) {
			return Mono.defer(() -> {
				if (this.index < filters.size()) {
					GatewayFilter filter = filters.get(this.index);
					DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
							this.index + 1);
					return filter.filter(exchange, chain);
				}
				else {
					return Mono.empty(); // complete
				}
			});
		}

	}

filter.filter(exchange, chain)依次执行过滤器, 前端获取过滤器时会对过滤器进行排序(实现了Order接口)

局部过滤器(GatewayFilter):应用到单个路由或者一个分组的路由上。
全局过滤器(GlobalFilter):应用到所有的路由上。
在组装过滤器链时会将GlobalFilter通过GatewayFilterAdapter(GatewayFilterAdapter implements GatewayFilter)转换成GatewayFilter进行链路调用

1.3.4 主要过滤器

1.3.4.1 RouteToRequestUrlFilter(全局处理区)

RouteToRequestUrlFilter根据路由查找服务
public class RouteToRequestUrlFilter implements GlobalFilter, Ordered

	/**
	 * 真实服务查找
	 * @param exchange the current server exchange
	 * @param chain provides a way to delegate to the next filter
	 * @return
	 */
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); //获取当前的route
		if (route == null) {
			return chain.filter(exchange);
		}
		log.trace("RouteToRequestUrlFilter start");
		//得到uri  = http://localhost:8001/driver/info/1?token=123456
		URI uri = exchange.getRequest().getURI();
		
		... 代码省略

		if ("lb".equalsIgnoreCase(routeUri.getScheme()) && routeUri.getHost() == null) {
			// Load balanced URIs should always have a host. If the host is null it is
			// most
			// likely because the host name was invalid (for example included an
			// underscore)
			throw new IllegalStateException("Invalid host: " + routeUri.toString());
		}
		//将uri换成 lb://hailtaxi-driver/driver/info/1?token=123456
		URI mergedUrl = UriComponentsBuilder.fromUri(uri)
				// .uri(routeUri)
				.scheme(routeUri.getScheme()).host(routeUri.getHost())
				.port(routeUri.getPort()).build(encoded).toUri();
		exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, mergedUrl);
		// 继续下一个过滤器
		return chain.filter(exchange);
	}

1.3.4.2 LoadBalancerClientFilter(负载均衡)

通过负载均衡得到真实服务的实例

	@Override
	@SuppressWarnings("Duplicates")
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR); // url:lb://hailtaxi-driver/driver/info/1?token=123456
		String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
		if (url == null
				|| (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
			return chain.filter(exchange);
		}
		// preserve the original url
		addOriginalRequestUrl(exchange, url);

		if (log.isTraceEnabled()) {
			log.trace("LoadBalancerClientFilter url before: " + url);
		}
		// 负载均衡选择服务实例
		final ServiceInstance instance = choose(exchange);

		if (instance == null) {
			throw NotFoundException.create(properties.isUse404(),
					"Unable to find instance for " + url.getHost());
		}
		//用户提交的URI = http://localhost:8001/driver/info/1?token=123456
		URI uri = exchange.getRequest().getURI();

		// if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
		// if the loadbalancer doesn't provide one.
		String overrideScheme = instance.isSecure() ? "https" : "http";
		if (schemePrefix != null) {
			overrideScheme = url.getScheme();
		}
		// 真正要请求的url = http://172.16.17.251:18081/driver/info/1?token=123456
		URI requestUrl = loadBalancer.reconstructURI(
				new DelegatingServiceInstance(instance, overrideScheme), uri);

		if (log.isTraceEnabled()) {
			log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
		}
		// 将真正要请求的url设置到上下文中
		exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
		return chain.filter(exchange);
	}

1.3.4.3 LoadBalancerClientFilter(远程调用)

代码太多就不说了, 主要是通过上面过滤器得到的服务实例, 发起远程调用的过程

2. open Feign 源码解析

2.1 openfeign 基础模型

对于使用openfeign而言,我们将对服务的http调用转换成对接口方法的调用。涉及的相关技术栈有:代理,http请求响应…
在这里插入图片描述

2.2 入口&流程

入口在@EnableFeignClients, 其中主要的是@Import注解中的FeignClientsRegistrar, 也就是open feign初始化的入口

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class) // 开启了 `FeignClient`扫描
public @interface EnableFeignClients {

接着进入FeignClientsRegistrar看, 关注其 registerBeanDefinitions 方法

/**
 *  ImportBeanDefinitionRegistrar:用于向容器中注入bean  关注其 registerBeanDefinitions 方法
 * @author Spencer Gibb
 * @author Jakub Narloch
 * @author Venil Noronha
 * @author Gang Li
 */
class FeignClientsRegistrar  implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
	...
		/**
	 * bean注入的 入口函数
	 * @param metadata
	 * @param registry
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
		// 完成 Feign 框架相关的配置注册
		registerDefaultConfiguration(metadata, registry);
		// 注册由 @FeignClient 修饰的接口 bean *****核心*****
		registerFeignClients(metadata, registry);
	}
	...
}

继续进入registerFeignClients

/**
	 * 向容器中注册由 @FeignClient 修饰的接口bean
	 * @param metadata  包含了@EnableFeignClients 注解的元信息
	 * @param registry
	 */
	public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
		// ClassPath Scanner
		ClassPathScanningCandidateComponentProvider scanner = getScanner();
		scanner.setResourceLoader(this.resourceLoader);
		// 接收 @EnableFeignClients(basePackages = {"com.itheima.driver.feign"})
		Set<String> basePackages;
		Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
		AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
		final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
		if (clients == null || clients.length == 0) {
			scanner.addIncludeFilter(annotationTypeFilter);
			// 获取 @EnableFeignClients中配置的 @FeignClient 接口扫描路径
			basePackages = getBasePackages(metadata);
		}else {
			... 代码省略
		}

		// 拿到  @EnableFeignClients 中配置的 @FeignClient 接口扫描路径 后开始 扫描
		for (String basePackage : basePackages) {
			// 查找 basePackage 包路径下所有 由 @FeignClient 修饰的候选bean,返回其 BeanDefinition 的集合
			Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);

			// 针对每个标注了 @FeignClient 的候选 BeanDefinition (接口的BeanDefinition) 准备向容器中注册
			for (BeanDefinition candidateComponent : candidateComponents) {
				if (candidateComponent instanceof AnnotatedBeanDefinition) {
					// verify annotated class is an interface
					AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
					AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
					Assert.isTrue(annotationMetadata.isInterface(),"@FeignClient can only be specified on an interface");// @FeignClient标注的必须是接口
					// 获取 @FeignClient 注解的相关属性信息
					Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
					// 获取@FeignClient(value = "hailtaxi-driver"),name属性,name属性和value属性是相同的含义,都是配置服务名
					String name = getClientName(attributes);// name = hailtaxi-driver
					registerClientConfiguration(registry, name, attributes.get("configuration"));
					//  针对当前标注了 @FeignClient 注解的候选接口 BeanDefinition   向容器中注册bean信息
					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}

这里面有一个有意思的就是通过spring的扫描器, 来扫描我们自定义的注解的接口

继续进入registerFeignClient(registry, annotationMetadata, attributes), 注册标注了 @FeignClient 注解的候选接口 BeanDefinition到spring容器

/**
 * 向容器中注册 每个标注了 @FeignClient 的接口bean
 * @param registry
 * @param annotationMetadata
 * @param attributes
 */
private void registerFeignClient(BeanDefinitionRegistry registry,
								 AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
	// 接口全路径
	String className = annotationMetadata.getClassName();// className=com.demo.driver.feign.DriverFeign
	/**
	 * 每个标注了@FeignClient 的接口,真正向容器中注册的其实是一个 FeignClientFactoryBean(实现了FactoryBean, 在dubbo中讲过)
	 * 1、创建 FeignClientFactoryBean的 BeanDefinition
	 * 2、向 BeanDefinition 中填充相关属性,属性来源于接口上@FeignClient的属性信息
	 */
	BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
	validate(attributes);// 验证fallback和fallbackFactory是不是接口
	
	// 添加发起请求需要的元数据信息
	definition.addPropertyValue("url", getUrl(attributes));
	definition.addPropertyValue("path", getPath(attributes));
	String name = getName(attributes);
	definition.addPropertyValue("name", name);
	String contextId = getContextId(attributes);
	definition.addPropertyValue("contextId", contextId);
	definition.addPropertyValue("type", className); // 把接口全路径也设置到 definition
	definition.addPropertyValue("decode404", attributes.get("decode404"));
	definition.addPropertyValue("fallback", attributes.get("fallback"));
	definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
	definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

	String alias = contextId + "FeignClient";
	AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();

	boolean primary = (Boolean) attributes.get("primary"); // has a default, won't be  null
	beanDefinition.setPrimary(primary);
	String qualifier = getQualifier(attributes);
	if (StringUtils.hasText(qualifier)) {
		alias = qualifier;
	}
	BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,new String[] { alias });
	BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
	/**
	 * 由于标注了@FeignClient的每个接口真正向容器中注册时注册的是与该接口相关的:FeignClientFactoryBean
	 * 而 FeignClientFactoryBean 实现了 FactoryBean 接口,也就是说当需要从容器中获取 这个bean时,获取出来的bean其实是由它的getObject方法返回的bean
	 *
	 * 所以:下一个入口是: FeignClientFactoryBean#getObject
	 */

}

生成接口代理的逻辑在FeignClientFactoryBean中, 也就是上面BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class), 关注FeignClientFactoryBean.getObject->getTarget

/**
 * 代理创建的入口,返回接口真正的实例
 * @return
 * @throws Exception
 */

@Override
public Object getObject() throws Exception {
	return getTarget();
}

<T> T getTarget() {
	/**
	 * FeignContext注册到容器是在 FeignAutoConfiguration 上完成的; 在初始化FeignContext时,会把 configurations 放入FeignContext中。
	 * configurations 的来源就是在前面 registerFeignClients 方法中 @FeignClient的配置 configuration。
	 */
	FeignContext context = this.applicationContext.getBean(FeignContext.class);
	//构建出Builder对象 用于构造代理对象,builder将会构建出 feign 的代理,
	Feign.Builder builder = feign(context);// builder= Feign$Builder
	if (!StringUtils.hasText(this.url)) { // 没在@FigenClient注解中配 url
		if (!this.name.startsWith("http")) {
			this.url = "http://" + this.name;
		}else {
			this.url = this.name;
		}
		this.url += cleanPath(); // this.url= http://hailtaxi-driver
		/**
		 * HardCodedTarget里封装了:接口type Class,服务名称,服务地址url ; 根据 Feign.Builder ,FeignContext,HardCodedTarget 构建 返回的对象
		 */
		return (T) loadBalance(builder, context,
				new HardCodedTarget<>(this.type, this.name, this.url));
	}

	if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
		this.url = "http://" + this.url;
	}
	String url = this.url + cleanPath();
	Client client = getOptional(context, Client.class);
	if (client != null) {
		if (client instanceof LoadBalancerFeignClient) {
			// not load balancing because we have a url,
			// but ribbon is on the classpath, so unwrap
			client = ((LoadBalancerFeignClient) client).getDelegate();
		}
		if (client instanceof FeignBlockingLoadBalancerClient) {
			// not load balancing because we have a url,
			// but Spring Cloud LoadBalancer is on the classpath, so unwrap
			client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
		}
		builder.client(client);
	}
	//生成默认代理类
	Targeter targeter = get(context, Targeter.class);
	return (T) targeter.target(this, builder, context,
			new HardCodedTarget<>(this.type, this.name, url));
}

在这里插入图片描述

因为没在@FigenClient注解中配 url, 所以会进入!StringUtils.hasText(this.url)中
FeignClientFactoryBean#loadBalance

protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) {
	// 获取feign 客户端,得到的是:LoadBalancerFeignClient  loadbalance基于 RibbonLoadBalanced  用于执行http请求
	Client client = getOptional(context, Client.class);
	if (client != null) {
		// 将 feign 的 Client 对象设置进 Feign.Builder
		builder.client(client);
		// Targeter默认是 HystrixTargeter 在 FeignAutoConfiguration 中有配置
		Targeter targeter = get(context, Targeter.class);
		/**
		 * 实例创建(开启熔断后具有熔断降级效果)
		 * this= FeignClientFactoryBean
		 * builder= Feign$Builder
		 * context = FeignContext
		 * target = HardCodedTarget
		 */
		return targeter.target(this, builder, context, target);
	}

	throw new IllegalStateException(
			"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
}

HystrixTargeter#target—>Feign.Builder#target

class HystrixTargeter implements Targeter {

	@Override
	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
			FeignContext context, Target.HardCodedTarget<T> target) {
		// 默认情况下 feign传递是:Feign$Builder
		if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
			return feign.target(target); // 直接进入到 Feign$Builder#target 方法中查看
		}
		feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
		String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName()  : factory.getContextId();
		SetterFactory setterFactory = getOptional(name, context, SetterFactory.class);
		if (setterFactory != null) {
			builder.setterFactory(setterFactory);
		}
		Class<?> fallback = factory.getFallback();
		if (fallback != void.class) {
			return targetWithFallback(name, context, target, builder, fallback);
		}
		Class<?> fallbackFactory = factory.getFallbackFactory();
		if (fallbackFactory != void.class) {
			return targetWithFallbackFactory(name, context, target, builder,fallbackFactory);
		}

		return feign.target(target);
	}
]

因为默认就是feign.hystrix.HystrixFeign.Builder, 所以直接进入HystrixFeign.Builder#target

public <T> T target(Target<T> target) {
  return build().newInstance(target);
}

1. Feign.Builder#build

public Feign build() {
  SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
      new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
          logLevel, decode404, closeAfterDecode, propagationPolicy);
  ParseHandlersByName handlersByName =
      new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
          errorDecoder, synchronousMethodHandlerFactory);
  return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}

在这里插入图片描述
2. ReflectiveFeign#newInstance

  @Override
  public <T> T newInstance(Target<T> target) {
  	// 获取方法名到方法处理器的映射
    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
    // 方法到方法处理器的映射(Method中包含@RequestMapping @RequestParms等注解)
    Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
    List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
	// 获取方法到方法处理器的映射
    for (Method method : target.type().getMethods()) {
      if (method.getDeclaringClass() == Object.class) {
        continue;
      } else if (Util.isDefault(method)) {
        DefaultMethodHandler handler = new DefaultMethodHandler(method);
        defaultMethodHandlers.add(handler);
        methodToHandler.put(method, handler);
      } else {
        methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
      }
    }
    // 根据目标对象生成代理拦截执行的handler
    InvocationHandler handler = factory.create(target, methodToHandler);
    // 使用jdk动态代理生成代理类, 重点关注InvocationHandler的invoic
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class<?>[] {target.type()}, handler);

    for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
      defaultMethodHandler.bindTo(proxy);
    }
    return proxy;
  }

在这里插入图片描述

2.2.* feign请求调用

ReflectiveFeign.FeignInvocationHandler#invoke
FeignInvocationHandler为ReflectiveFeign的内部类

static class FeignInvocationHandler implements InvocationHandler {

  private final Target target;
  private final Map<Method, MethodHandler> dispatch;

  FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
    this.target = checkNotNull(target, "target");
    this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if ("equals".equals(method.getName())) {
      try {
        Object otherHandler =
            args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
        return equals(otherHandler);
      } catch (IllegalArgumentException e) {
        return false;
      }
    } else if ("hashCode".equals(method.getName())) {
      return hashCode();
    } else if ("toString".equals(method.getName())) {
      return toString();
    }

    return dispatch.get(method).invoke(args);
  }
}

dispatch中存储的是方法到方法处理器的映射
从Map中根据Method获取该方法的处理器(SynchronousMethodHandler), 然后执行

SynchronousMethodHandler#invoke

@Override
public Object invoke(Object[] argv) throws Throwable {
  RequestTemplate template = buildTemplateFromArgs.create(argv);
  Options options = findOptions(argv);
  Retryer retryer = this.retryer.clone();
  while (true) {
    try {
      return executeAndDecode(template, options);
    } catch (RetryableException e) {
      try {
        retryer.continueOrPropagate(e);
      } catch (RetryableException th) {
        Throwable cause = th.getCause();
        if (propagationPolicy == UNWRAP && cause != null) {
          throw cause;
        } else {
          throw th;
        }
      }
      if (logLevel != Logger.Level.NONE) {
        logger.logRetry(metadata.configKey(), logLevel);
      }
      continue;
    }
  }
}

在这里插入图片描述
继续看executeAndDecode方法, 从名字可以看出实执行真正的请求
后面正对请求的代码就不看了, 无非就是请求负载均衡之类的, 总体openFeign的代码流程比较清晰

小插曲: feign前面为什么要加open, 是因为feign中有自己的注解, 很不方便; springcloud整合后, 可以正常使用@RequestMapping等注解, 就叫openfeign了

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。