Order
This article mainly studies the Targeter of spring cloud openfeign.
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 defines a target method that receives parameters of type 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 implements the Targeter interface, and its Target method directly uses the Feign.Builder.target method.
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 interface defines type, name, url, apply method
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 implements the Target interface. Its constructor receives the type, name, and url parameters. Its apply method sets the Target of requestTemplate as the url if the url starts with http, and then constructs the Request to return
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 implements the Targeter interface. its target method first determines whether the Feign.Builder type is feign.hystrix.hystrixfeign.buil der, and if not, directly executes the feign.target(target) return
- Use targetWithFallback to construct fallback that is not void.class; The fallbackFactory is not constructed for void.class using targetWithFallbackFactory; If none of them is true, execute feign.target(target) return
- The targetWithfallbackFactoryï¼› method uses the FallbackFactory when it is constructed using the target of HystrixFeign.Builder; The targetWithFallback method uses 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 creates HystrixTargeter when Feign. HyStrix. HyStrixEign is present, otherwise it creates DefaultTargeter
Summary
- Targeter defines a target method that receives parameters of type FeignClientFactoryBean, Feign.Builder, FeignContext, Target.HardCodedTarget
- Defaulttargeter implements the Targeter interface, and its Target method directly uses the Feign.Builder.target method.
- HystrixTargeter implements the Targeter interface. its target method first determines whether the Feign.Builder type is feign.hystrix.hystrixfeign.buil der, and if not, directly executes the feign.target(target) return. Otherwise, use targetWithFallback to construct fallback that is not void.class; The fallbackFactory is not constructed for void.class using targetWithFallbackFactory; If none of them is true, execute feign.target(target) return