SpringCloud高级应用-源码解析
- 1. gateway 源码解析
- 1.1 自动装配
- 1.2 核心装配
- 1.2.1 GatewayClassPathWarningAutoConfiguration
- 1.2.2 GatewayAutoConfiguration
- 1.2.3 GatewayLoadBalancerClientAutoConfiguration
- 1.2.4 GatewayRedisAutoConfiguration
- 1.3 Gateway 工作机制
- 1.3.1 Gateway的三个核心组件
- 1.3.2 请求处理流程(图)
- 1.3.3 入口&流程
- 1.3.4 主要过滤器
- 1.3.4.1 RouteToRequestUrlFilter(全局处理区)
- 1.3.4.2 LoadBalancerClientFilter(负载均衡)
- 1.3.4.3 LoadBalancerClientFilter(远程调用)
- 2. open Feign 源码解析
- 2.1 openfeign 基础模型
- 2.2 入口&流程
- 2.2.* feign请求调用
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 = "\n\n**********************************************************\n\n";
/**
* 非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
- 网关的开启与关闭
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
- 初始化 NettyConfiguration
/**
* 初始化 NettyConfiguration
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HttpClient.class)
protected static class NettyConfiguration {
...
}
- 初始化 GlobalFilter
// GlobalFilter beans 初始化各种内置的 GlobalFilter
@Bean
public AdaptCachedBodyGlobalFilter adaptCachedBodyGlobalFilter() {
return new AdaptCachedBodyGlobalFilter();
}
- 初始化 FilteringWebHandler
@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
return new FilteringWebHandler(globalFilters);
}
- 初始化 GatewayProperties
- 初始化 PrefixPathGatewayFilterFactory
- 初始化 RoutePredicateFactory
- 初始化 RouteDefinitionLocator
- 初始化 RouteLocator
- 初始化 RoutePredicateHandlerMapping
- 初始化 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 工作机制
- Gateway 接收客户端请求
- 客户端请求与路由信息进行匹配,匹配成功的才能够被路由转发到相应的下游服务
- 请求经过 Filter 过滤器链,执行 pre 处理逻辑,如修改请求头信息等
- 请求被转发至下游服务并返回响应
- 响应经过 Filter 过滤器链,执行 post 处理逻辑
- 向客户端响应应答
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了