共计 6652 个字符,预计需要花费 17 分钟才能阅读完成。
序
本文主要研究一下 spring cloud openfeign 的 Targeter
Targeter
spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/Targeter.java
interface Targeter { | |
<T> T target(FeignClientFactoryBean factory, Feign.Builder feign, | |
FeignContext context, Target.HardCodedTarget<T> target); | |
} |
- Targeter 定义了 target 方法,它接收 FeignClientFactoryBean、Feign.Builder、FeignContext、Target.HardCodedTarget 类型的参数
DefaultTargeter
spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/DefaultTargeter.java
class DefaultTargeter implements Targeter { | |
@Override | |
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, | |
FeignContext context, Target.HardCodedTarget<T> target) {return feign.target(target); | |
} | |
} |
- DefaultTargeter 实现了 Targeter 接口,它的 target 方法直接使用的是 Feign.Builder.target 方法
Target
feign-core-10.2.3-sources.jar!/feign/Target.java
public interface Target<T> {/* The type of the interface this target applies to. ex. {@code Route53}. */ | |
Class<T> type(); | |
/* configuration key associated with this target. For example, {@code route53}. */ | |
String name(); | |
/* base HTTP URL of the target. For example, {@code https://api/v2}. */ | |
String url(); | |
public Request apply(RequestTemplate input); | |
//...... | |
} |
- Target 接口定义了 type、name、url、apply 方法
HardCodedTarget
feign-core-10.2.3-sources.jar!/feign/Target.java
public static class HardCodedTarget<T> implements Target<T> { | |
private final Class<T> type; | |
private final String name; | |
private final String url; | |
public HardCodedTarget(Class<T> type, String url) {this(type, url, url); | |
} | |
public HardCodedTarget(Class<T> type, String name, String url) {this.type = checkNotNull(type, "type"); | |
this.name = checkNotNull(emptyToNull(name), "name"); | |
this.url = checkNotNull(emptyToNull(url), "url"); | |
} | |
@Override | |
public Class<T> type() {return type;} | |
@Override | |
public String name() {return name;} | |
@Override | |
public String url() {return url;} | |
/* no authentication or other special activity. just insert the url. */ | |
@Override | |
public Request apply(RequestTemplate input) {if (input.url().indexOf("http") != 0) {input.target(url()); | |
} | |
return input.request();} | |
@Override | |
public boolean equals(Object obj) {if (obj instanceof HardCodedTarget) {HardCodedTarget<?> other = (HardCodedTarget) obj; | |
return type.equals(other.type) | |
&& name.equals(other.name) | |
&& url.equals(other.url); | |
} | |
return false; | |
} | |
@Override | |
public int hashCode() { | |
int result = 17; | |
result = 31 * result + type.hashCode(); | |
result = 31 * result + name.hashCode(); | |
result = 31 * result + url.hashCode(); | |
return result; | |
} | |
@Override | |
public String toString() {if (name.equals(url)) {return "HardCodedTarget(type=" + type.getSimpleName() + ", url=" + url + ")"; | |
} | |
return "HardCodedTarget(type=" + type.getSimpleName() + ", name=" + name + ", url=" + url | |
+ ")"; | |
} | |
} |
- HardCodedTarget 实现了 Target 接口,其构造器接收 type、name、url 参数,其 apply 方法对于 url 是 http 开头的则设置 RequestTemplate 的 target 为 url,然后构造 request 返回
HystrixTargeter
spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/HystrixTargeter.java
class HystrixTargeter implements Targeter { | |
@Override | |
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, | |
FeignContext context, Target.HardCodedTarget<T> target) {if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {return feign.target(target); | |
} | |
feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign; | |
SetterFactory setterFactory = getOptional(factory.getName(), context, | |
SetterFactory.class); | |
if (setterFactory != null) {builder.setterFactory(setterFactory); | |
} | |
Class<?> fallback = factory.getFallback(); | |
if (fallback != void.class) {return targetWithFallback(factory.getName(), context, target, builder, | |
fallback); | |
} | |
Class<?> fallbackFactory = factory.getFallbackFactory(); | |
if (fallbackFactory != void.class) {return targetWithFallbackFactory(factory.getName(), context, target, builder, | |
fallbackFactory); | |
} | |
return feign.target(target); | |
} | |
private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context, | |
Target.HardCodedTarget<T> target, HystrixFeign.Builder builder, | |
Class<?> fallbackFactoryClass) {FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext( | |
"fallbackFactory", feignClientName, context, fallbackFactoryClass, | |
FallbackFactory.class); | |
return builder.target(target, fallbackFactory); | |
} | |
private <T> T targetWithFallback(String feignClientName, FeignContext context, | |
Target.HardCodedTarget<T> target, HystrixFeign.Builder builder, | |
Class<?> fallback) { | |
T fallbackInstance = getFromContext("fallback", feignClientName, context, | |
fallback, target.type()); | |
return builder.target(target, fallbackInstance); | |
} | |
private <T> T getFromContext(String fallbackMechanism, String feignClientName, | |
FeignContext context, Class<?> beanType, Class<T> targetType) {Object fallbackInstance = context.getInstance(feignClientName, beanType); | |
if (fallbackInstance == null) { | |
throw new IllegalStateException(String.format( | |
"No" + fallbackMechanism | |
+ "instance of type %s found for feign client %s", | |
beanType, feignClientName)); | |
} | |
if (!targetType.isAssignableFrom(beanType)) { | |
throw new IllegalStateException(String.format("Incompatible" | |
+ fallbackMechanism | |
+ "instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s", | |
beanType, targetType, feignClientName)); | |
} | |
return (T) fallbackInstance; | |
} | |
private <T> T getOptional(String feignClientName, FeignContext context, | |
Class<T> beanType) {return context.getInstance(feignClientName, beanType); | |
} | |
} |
- HystrixTargeter 实现了 Targeter 接口,其 target 方法首先判断 Feign.Builder 类型是否是 feign.hystrix.HystrixFeign.Builder,不是的话直接执行 feign.target(target) 返回
- 对于 fallback 不为 void.class 的使用 targetWithFallback 进行构造;对于 fallbackFactory 不为 void.class 的使用 targetWithFallbackFactory 进行构造;都不是的话则执行 feign.target(target) 返回
- targetWithFallbackFactory 方法使用 HystrixFeign.Builder 的 target 进行构造时使用的是 fallbackFactory;而 targetWithFallback 方法使用的是 fallbackInstance
FeignAutoConfiguration
spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/FeignAutoConfiguration.java
@Configuration | |
@ConditionalOnClass(Feign.class) | |
@EnableConfigurationProperties({ FeignClientProperties.class, | |
FeignHttpClientProperties.class }) | |
public class FeignAutoConfiguration { | |
//...... | |
@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(); | |
} | |
} | |
//...... | |
} |
- FeignAutoConfiguration 在有 feign.hystrix.HystrixFeign 时创建的是 HystrixTargeter,否则创建的是 DefaultTargeter
小结
- Targeter 定义了 target 方法,它接收 FeignClientFactoryBean、Feign.Builder、FeignContext、Target.HardCodedTarget 类型的参数
- DefaultTargeter 实现了 Targeter 接口,它的 target 方法直接使用的是 Feign.Builder.target 方法
- HystrixTargeter 实现了 Targeter 接口,其 target 方法首先判断 Feign.Builder 类型是否是 feign.hystrix.HystrixFeign.Builder,不是的话直接执行 feign.target(target) 返回;否则对于 fallback 不为 void.class 的使用 targetWithFallback 进行构造;对于 fallbackFactory 不为 void.class 的使用 targetWithFallbackFactory 进行构造;都不是的话则执行 feign.target(target) 返回
doc
- Targeter
正文完