FeignClientFactoryBean 分析
1、类图
实现了spring InitlizaingBean接口的 afterPropertiest()方法
实现了FactoryBean 实现了里面getObject()方法
实现了ApplicationContextAware接口 里面的setApplicationContext()方法
2、afterPropertiest()方法
@Override
public void afterPropertiesSet() throws Exception {
Assert.hasText(this.contextId, "Context id must be set");
Assert.hasText(this.name, "Name must be set");
}
3、getObject()方法
@Override
public Object getObject() throws Exception {
return getTarget();
}
<T> T getTarget() {
//从application中获取FeignContext通过FeignAutoConfiguration自动装配导入的
FeignContext context = this.applicationContext.getBean(FeignContext.class);
//调用feign方法获取feign的budiler构造器 并设置feign的相关属性 如level,retryer,errorDecoder,options 以及RequestInterceptor和decode404配置
Feign.Builder builder = feign(context);
//判断url属性是否空 为空的话创建 loadBalance负载均衡客户端
if (!StringUtils.hasText(this.url)) {
//判断name属性是否为http开头
if (!this.name.startsWith("http")) {
//url属性为 http://serviceId 格式
this.url = "http://" + this.name;
}
else {
this.url = this.name;
}
//url属性path处理 1、去除空格 2、如果不是以/开头添加/ 3、结尾如果是/ 去掉/结尾
this.url += cleanPath();
//构建loadBlacnce客户端
return (T) loadBalance(builder, context,
new HardCodedTarget<>(this.type, this.name, this.url));
}
//如果url不为空 并且url不是http开头 url重新赋值 前面添加http://
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
//url属性path处理 1、去除空格 2、如果不是以/开头添加/ 3、结尾如果是/ 去掉/结尾
String url = this.url + cleanPath();
//获取客户端
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
//不是负载平衡,因为我们有一个url,但是ribbon在类路径上,所以unwrap
//LoadBalancerFeignClient
client = ((LoadBalancerFeignClient) client).getDelegate();
}
//设置feign的client属性
builder.client(client);
}
//获取 targeter
Targeter targeter = get(context, Targeter.class);
return (T) targeter.target(this, builder, context,
new HardCodedTarget<>(this.type, this.name, url));
}
protected Feign.Builder feign(FeignContext context) {
//获取FeignLoggerFactory 从FeignContext中获取 最终会调到夫类 NamedContextFactory 会根据每个 contectId创建一个
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
//创建日志类 没有配置默认Slf4jLogger
Logger logger = loggerFactory.create(this.type);
//构建feign.builder从NamedContextFactory中的AnnotationConfigApplicationContext中获取
Feign.Builder builder = get(context, Feign.Builder.class)
//设置日志类
.logger(logger)
//PageableSpringEncoder 在FeignClientsConfiguration中注入
.encoder(get(context, Encoder.class))
//OptionalDecoder 在FeignClientsConfiguration中注入
.decoder(get(context, Decoder.class))
//SpringMvcContract 在FeignClientsConfiguration中注入
.contract(get(context, Contract.class));
//配置feign属性日志level,retryer,errorDecoder,options 以及RequestInterceptor和decode404配置
configureFeign(context, builder);
return builder;
}
protected void configureFeign(FeignContext context, Feign.Builder builder) {
//从容器中获取FeignClientProperties通过FeignAutoConfiguration 自动装类导入配置
FeignClientProperties properties = this.applicationContext
.getBean(FeignClientProperties.class);
if (properties != null) {
//创建后默认为true
if (properties.isDefaultToProperties()) {
//从配置类中设置配置 根据contextId从获取bean配置
configureUsingConfiguration(context, builder);
//从配置文件中 获取Default配置
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
//根据contextId获取Properties进行配置
configureUsingProperties(properties.getConfig().get(this.contextId),builder);
}
else {
//设置properties中Default配置
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()),builder);
//设置propertiest中单个服务配置
configureUsingProperties(properties.getConfig().get(this.contextId),builder);
//使用spring容器中的bean配置
configureUsingConfiguration(context, builder);
}
}
else {
//如果获取的到的properties不为空 直接通过配置类设置
configureUsingConfiguration(context, builder);
}
}
从容器中获取
protected void configureUsingConfiguration(FeignContext context,
Feign.Builder builder) {
//获取日志级别
Logger.Level level = getOptional(context, Logger.Level.class);
if (level != null) {
builder.logLevel(level);
}
//获取重试
Retryer retryer = getOptional(context, Retryer.class);
if (retryer != null) {
builder.retryer(retryer);
}
//获取错误编码器默认 null
ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
if (errorDecoder != null) {
builder.errorDecoder(errorDecoder);
}
//获取超时配置 默认链接超时10s 读超时60s
Request.Options options = getOptional(context, Request.Options.class);
if (options != null) {
builder.options(options);
}
//获取feign拦截器配置
Map<String, RequestInterceptor> requestInterceptors = context
.getInstances(this.contextId, RequestInterceptor.class);
if (requestInterceptors != null) {
builder.requestInterceptors(requestInterceptors.values());
}
//设置404
if (this.decode404) {
builder.decode404();
}
}
protected void configureUsingProperties(
FeignClientProperties.FeignClientConfiguration config,
Feign.Builder builder) {
if (config == null) {
return;
}
//判断如果日志级别不为空配置日志级别
if (config.getLoggerLevel() != null) {
builder.logLevel(config.getLoggerLevel());
}
//判断链接超时时间和读超时时间不为空设置
if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
builder.options(new Request.Options(config.getConnectTimeout(),
config.getReadTimeout()));
}
//配置retryer重试不为空配置
if (config.getRetryer() != null) {
Retryer retryer = getOrInstantiate(config.getRetryer());
builder.retryer(retryer);
}
//判断错误编码不为空 进行设置
if (config.getErrorDecoder() != null) {
ErrorDecoder errorDecoder = getOrInstantiate(config.getErrorDecoder());
builder.errorDecoder(errorDecoder);
}
//拦截器不为空设置
if (config.getRequestInterceptors() != null
&& !config.getRequestInterceptors().isEmpty()) {
// 这将把请求拦截器添加到构建器中,而不是替换现有的
for (Class<RequestInterceptor> bean : config.getRequestInterceptors()) {
RequestInterceptor interceptor = getOrInstantiate(bean);
builder.requestInterceptor(interceptor);
}
}
//404页面不为空设置
if (config.getDecode404() != null) {
if (config.getDecode404()) {
builder.decode404();
}
}
if (Objects.nonNull(config.getEncoder())) {
builder.encoder(getOrInstantiate(config.getEncoder()));
}
if (Objects.nonNull(config.getDecoder())) {
builder.decoder(getOrInstantiate(config.getDecoder()));
}
//设置契约为springmvc 默认实现
if (Objects.nonNull(config.getContract())) {
builder.contract(getOrInstantiate(config.getContract()));
}
}
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
//获取client 接口实现类型默认实现为 LoadBalancerFeignClient
Client client = getOptional(context, Client.class);
if (client != null) {
//构建client
builder.client(client);
//获取targeter 有2种 1、DefaultTargeter 2、HystrixTargeter 如果引入Hystrix类则为HystrixTargeter
Targeter targeter = get(context, Targeter.class);
//最终获取到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?");
}
DefaultTargeter和HystrixTargeter 注入条件
@Configuration
@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
protected static class HystrixFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
return new HystrixTargeter();
}
}
@Configuration
@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
protected static class DefaultFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
return new DefaultTargeter();
}
}
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
//判断是否为feign.hystrix.HystrixFeign.Builder类型直接 使用feign.target方法创建动态代理
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
return feign.target(target);
}
//如果不是强转类型 设置feign属性 使用feign.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);
}
public <T> T target(Target<T> target) {
//builde()方法 创建同步执行的方法处理器工厂,放入到名称解析处理器中 创建反射的ReflectiveFeign对象
//调用ReflectiveFeign.newInstance(target) 里面包括对fegin接口校验以及feign注解的解析
return build().newInstance(target);
}
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);
//创建反射的feign
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
最终会走到 feign反射类 ReflectiveFeign类的newInstance方法里面 创建动态代理
@Override
public <T> T newInstance(Target<T> target) {
//校验并解析feign类以及方法的@RequestMapping注解 并解析参数的注解,以及返回值类型
//再加上feign的配置信息 组装成一个key为 类#方法名(参数) value为SynchronousMethodHandler类型的map
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
//下面循环主要是为 1、获取默认方法下面会绑定代理类, 2、nameToHandler 转换成 methodToHandler
for (Method method : target.type().getMethods()) {
//如果method归属于object类型跳过
if (method.getDeclaringClass() == Object.class) {
continue;
}
//如果method是默认的 添加到 defaultMethodHandlers 和methodToHandler 中
else if (Util.isDefault(method)) {
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
}
else {
//将nameToHandler中的key由string类型转变成method类型 value是 SynchronousMethodHanlder
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
//创建出来一个FeignInvocationHandler
InvocationHandler handler = factory.create(target, methodToHandler);
//创建动态代理类
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()},
handler);
//为默认方法绑定 代理类
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
ParseHandlersByName的apply方法
public Map<String, MethodHandler> apply(Target key) {
//解析所有的类 方法以及参数 返回值 返回list
List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
//创建结果map
Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
//便利元数据信息
for (MethodMetadata md : metadata) {
BuildTemplateByResolvingArgs buildTemplate;
//从参数构建表单编码模板
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
}
//从参数构建编码模板
else if (md.bodyIndex() != null) {
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
}
//通过解析参数来构建模板
else {
buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder);
}
//添加到map中 value为 SynchronousMethodHandler 线程安全的 MethodHandler
result.put(md.configKey(),
factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
}
return result;
}
SpringMvcContract实现了 Abstract BaseContract 类型
@Override
public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
// 它返回一个TypeVariable数组,该数组表示由泛型声明定义的变量类型。
//当基础泛型声明未定义任何变量类型时,它将返回 0
checkState(targetType.getTypeParameters().length == 0,"Parameterized types unsupported: %s", targetType.getSimpleName());
//只支持单级继承
checkState(targetType.getInterfaces().length <= 1,"Only single inheritance supported: %s",targetType.getSimpleName());
//只支持单级继承
if (targetType.getInterfaces().length == 1) {
checkState(targetType.getInterfaces()[0].getInterfaces().length == 0,"Only single-level inheritance supported: %s",targetType.getSimpleName());
}
//创建map存储
Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
for (Method method : targetType.getMethods()) {
//判断此方法不是obejct类的方法 hashCode() equals() clone() 方法等
if (method.getDeclaringClass() == Object.class ||
//判断不是一个静态方法
(method.getModifiers() & Modifier.STATIC) != 0 ||
//判断不是默认方法
Util.isDefault(method)) {
continue;
}
//解析方法元数据信息 子类重写了夫类 具体看子类SpringMvcContract中实现
MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
//判断result是否有@Override 注解
checkState(!result.containsKey(metadata.configKey()), "Overrides unsupported: %s",
metadata.configKey());
//添加到map中
result.put(metadata.configKey(), metadata);
}
return new ArrayList<>(result.values());
}
SpringMvcContract类中 parseAndValidateMetadata方法
@Override
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
//已经处理的方法放入到map中 key生成策略类#方法名(参数) DingTalkFeign#send(DingWebhookDTO,String)
this.processedMethods.put(Feign.configKey(targetType, method), method);
//使用父类(BaseContract)解析获取方法元数据信息
MethodMetadata md = super.parseAndValidateMetadata(targetType, method);
//获取类上的@RequestMapping注解
RequestMapping classAnnotation = findMergedAnnotation(targetType,
RequestMapping.class);
//设置类上面@RequestMapping注解 只有当方法上面没有指定属性时 类上面指定的属性才生效
if (classAnnotation != null) {
// acceept请求头配置
if (!md.template().headers().containsKey(ACCEPT)) {
parseProduces(md, method, classAnnotation);
}
//content-type请求头配置
if (!md.template().headers().containsKey(CONTENT_TYPE)) {
parseConsumes(md, method, classAnnotation);
}
//类的注解是从方法那里拿过来的 如果有的话,一定要写这些
parseHeaders(md, method, classAnnotation);
}
return md;
}
BaseContract中parseAndValidateMetadata方法
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
//创建MethodMetadata对象
MethodMetadata data = new MethodMetadata();
//解析并设置返回值类型 里面解析逻辑比较复杂 涉及到递归解析
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
//生成并设置configKey
data.configKey(Feign.configKey(targetType, method));
//使用子类SpringMvcContract处理类上面加@RequestMapper的uri 并设置template的uri信息
if (targetType.getInterfaces().length == 1) {
processAnnotationOnClass(data, targetType.getInterfaces()[0]);
}
processAnnotationOnClass(data, targetType);
//解析每个方法上的@ReuqestMapping注解包括对方法返回值,请求uri以及请求头和参数@Param注解的处理
for (Annotation methodAnnotation : method.getAnnotations()) {
processAnnotationOnMethod(data, methodAnnotation, method);
}
//检测方法的http method不能为空
checkState(data.template().method() != null,
"Method %s not annotated with HTTP method type (ex. GET, POST)",
method.getName());
//获取参数类类型
Class<?>[] parameterTypes = method.getParameterTypes();
//获取参数的范型类型
Type[] genericParameterTypes = method.getGenericParameterTypes();
//获取参数注解二维数组
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
//获取长度
int count = parameterAnnotations.length;
//遍历
for (int i = 0; i < count; i++) {
boolean isHttpAnnotation = false;
if (parameterAnnotations[i] != null) {
//判断参数是否包含1、PathVariable 2、RequestParam 3、RequestHeader 4、SpringQueryMap 这个4个注解
//使用相应的处理器处理完成之后 设置到RequestTemplate中
isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
}
//判断是否为uri类型
if (parameterTypes[i] == URI.class) {
data.urlIndex(i);
}
//如果非上面4个注解,并且参数类型不是options类型
else if (!isHttpAnnotation && parameterTypes[i] != Request.Options.class) {
//主体参数不能与表单参数一起使用(body和表单不能同时使用)
checkState(data.formParams().isEmpty(),
"Body parameters cannot be used with form parameters.");
//方法有太多的Body参数
checkState(data.bodyIndex() == null, "Method has too many Body parameters: %s", method);
//设置body请求体下标
data.bodyIndex(i);
//解析body类型 根返回值解析一个方法 比较复杂包含了 递归
data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i]));
}
}
//如果headerMapIndex不为空
if (data.headerMapIndex() != null) {
//校验参数类型必须为map 检查key必须为String类型 直接传入HeaderMap固定值
checkMapString("HeaderMap", parameterTypes[data.headerMapIndex()],
genericParameterTypes[data.headerMapIndex()]);
}
//查询的queryMap校验 和上面一样的规则
if (data.queryMapIndex() != null) {
if (Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()])) {
checkMapKeys("QueryMap", genericParameterTypes[data.queryMapIndex()]);
}
}
//返回方法元数据信息
return data;
}
SpringMvcContract中processAnnotationOnClass方法
@Override
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
if (clz.getInterfaces().length == 0) {
//获取类上面的@RequestMapping注解添加到 MethodMetadata.RequestTemplate.uri中
RequestMapping classAnnotation = findMergedAnnotation(clz,
RequestMapping.class);
if (classAnnotation != null) {
// 如果指定,则从类注释中预先添加路径
if (classAnnotation.value().length > 0) {
String pathValue = emptyToNull(classAnnotation.value()[0]);
//占位符处理
pathValue = resolve(pathValue);
//非/开头 添加/
if (!pathValue.startsWith("/")) {
pathValue = "/" + pathValue;
}
data.template().uri(pathValue);
}
}
}
}
SpringMvcContract中processAnnotationOnMethod方法
@Override
protected void processAnnotationOnMethod(MethodMetadata data,
Annotation methodAnnotation, Method method) {
//判断方法的注解上必须有@RequestMapping
if (!RequestMapping.class.isInstance(methodAnnotation) && !methodAnnotation
.annotationType().isAnnotationPresent(RequestMapping.class)) {
return;
}
//获取@RequestMapping注解
RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);
// 获取HTTP Method 如果没有定义默认为RequestMethod.GET
RequestMethod[] methods = methodMapping.method();
if (methods.length == 0) {
methods = new RequestMethod[] { RequestMethod.GET };
}
//检查@RequestMapping注解中只能有一个 http method
checkOne(method, methods, "method");
//设置元方法数据的请求 RequestTamplate属性的method
data.template().method(Request.HttpMethod.valueOf(methods[0].name()));
//检查@RequestMapping value 属性 values != null && (values.length == 0 || values.length == 1)
checkAtMostOne(method, methodMapping.value(), "value");
//如果@ReuqestMapping中的value值不为空 进行url解析 追加 到data中的RequestTemplate属性的uri
if (methodMapping.value().length > 0) {
String pathValue = emptyToNull(methodMapping.value()[0]);
if (pathValue != null) {
//占位符处理
pathValue = resolve(pathValue);
//如果不是以"/"开头 添加"/"
if (!pathValue.startsWith("/") && !data.template().path().endsWith("/")) {
pathValue = "/" + pathValue;
}
data.template().uri(pathValue, true);
}
}
//解析@RequestMapping 中produces属性 进行 data中ReqeustTemplate的header中的accept设置
//md.template().header(ACCEPT, clientAccepts);
parseProduces(data, method, methodMapping);
//解析@RequestMapping 中consumes属性 进行 data中ReqeustTemplate的header设置中的content-type设置
parseConsumes(data, method, methodMapping);
//解析@RequestMapping 中headers属性 对"name=value" 进行处理并添加到 headers中 里面包含了占位符处理逻辑
parseHeaders(data, method, methodMapping);
//参数处理将@Param注解和参数的下标绑定起来
data.indexToExpander(new LinkedHashMap<Integer, Param.Expander>());
}
SpringMvcContract中processAnnotationsOnParameter方法
@Override
protected boolean processAnnotationsOnParameter(MethodMetadata data,
Annotation[] annotations, int paramIndex) {
//是否为http注解
boolean isHttpAnnotation = false;
//定义注解参数处理器
AnnotatedParameterProcessor.AnnotatedParameterContext context = new SimpleAnnotatedParameterContext(
data, paramIndex);
//从缓存中根据 configKey获取method
Method method = this.processedMethods.get(data.configKey());
//遍历处理注解
for (Annotation parameterAnnotation : annotations) {
//annotatedArgumentProcessors的数据类型Map<Class<? extends Annotation>, AnnotatedParameterProcessor>
//key为注解,value为处理类,总共有4个注解和处理类
//1、PathVariable 2、RequestParam 3、RequestHeader 4、SpringQueryMap
AnnotatedParameterProcessor processor = this.annotatedArgumentProcessors
.get(parameterAnnotation.annotationType());
//获取到处理类不为空
if (processor != null) {
Annotation processParameterAnnotation;
// synthesize, handling @AliasFor, while falling back to parameter name on missing String #value():
processParameterAnnotation = synthesizeWithMethodParameterNameAsFallbackValue(
parameterAnnotation, method, paramIndex);
//处理注解参数
isHttpAnnotation |= processor.processArgument(context,
processParameterAnnotation, method);
}
}
//如果是http注解并且下标取值不为空
if (isHttpAnnotation && data.indexToExpander().get(paramIndex) == null) {
//创建参数类型 里面包括了对Iterable类型的处理
TypeDescriptor typeDescriptor = createTypeDescriptor(method, paramIndex);
//判断参数类型是否可以转换成String类型
if (this.conversionService.canConvert(typeDescriptor,
STRING_TYPE_DESCRIPTOR)) {
Param.Expander expander = this.convertingExpanderFactory
.getExpander(typeDescriptor);
if (expander != null) {
//将expander(一个lambda表达式) 放入到data中
data.indexToExpander().put(paramIndex, expander);
}
}
}
return isHttpAnnotation;
}