序
本文主要研究一下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)返回
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。