基于NetFlix Feign实现,整合了SpringCloud Ribbon 和 SpringCloud hystrix, 同时封装了Http调用流程,更适合面向接口化的编程习惯
该图片摘自https://www.jianshu.com/p/8c7b92b4396c
以下解析源自版本
springBoot 2.1.3.RELEASE
springCloud Greenwich.RELEASE
一、快速入门
maven
<!--客户端eureka注册-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--使用feign、包含ribbon、hystrix整合-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
服务接口
/**
* 此接口是由serverId为car的服务暴露和实现,通过eureka、@RequestMapping等获取具体的请求ip和请求路径
*/
@FeignClient("car")
@RequestMapping("/car")
public interface CarClient {
@GetMapping("/getCarNo")
ResultModelDTO<String> getCarNo();
@GetMapping("/getCarNoQuery")
ResultModelDTO<String> getCarNoQuery(@RequestParam("carNo") String carNo);
}
请求方
@SpringBootApplication
@EnableDiscoveryClient //eureka客户端注册
@EnableFeignClients("com.zkml")//支持feign
public class CarFacadeApplication {
public static void main(String[] args) {
SpringApplication.run(CarFacadeApplication.class, args);
}
}
@RestController
public class TestFeignController {
@Autowired
CarClient carClient;
@RequestMapping("/getCarNoQuery")
public ResultModelDTO<String> getCarNoQuery(String carNo){
return carClient.getCarNoQuery(carNo);
}
}
服务方
@RestController
public class CarController implements CarClient{
public ResultModelDTO<String> getCarNo(){
return ResultModelUtil.successResult("皖123456");
}
@Override
public ResultModelDTO<String> getCarNoQuery(String carNo) {
return ResultModelUtil.successResult(carNo);
}
}
二、源码解析
1、扫描注入FeignClient注解接口
在请求方的启动类上有一个@EnableFeignClients注解,表示启用feign
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
//略
}
主要扫描注入逻辑在FeignClientsRegistrar,这个类实现了ImportBeanDefinitionRegistrar接口, springBoot会调用registerBeanDefinitions方法动态注入bean
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//如果在@EnableFeignClients中配置了defaultConfiguration,则在这里进行处理
//包装成FeignClientSpecification类进行注入
registerDefaultConfiguration(metadata, registry);
//1、根据@EnableFeignClients中配置的value、basePackages、basePackageClasses、clients扫描相应的包,获取@FeignClient注解的接口集合
//2、把目标接口名称以及@FeignClient各项参数包装成FeignClientFactoryBean类进行注入
registerFeignClients(metadata, registry);
}
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//略去部分代码
for (String basePackage : basePackages) {
Set<BeanDefinition> candidateComponents = scanner
.findCandidateComponents(basePackage);
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");
Map<String, Object> attributes = annotationMetadata
.getAnnotationAttributes(
FeignClient.class.getCanonicalName());
//这里的name依次根据contextId、value、name、serviceId获取
String name = getClientName(attributes);
//FeignClient的配置类包装成FeignClientSpecification类进行注入
registerClientConfiguration(registry, name,
attributes.get("configuration"));
//注入目标接口
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}
//把目标接口名称以及@FeignClient各项参数包装成FeignClientFactoryBean类进行注入
private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
//基于FeignClientFactoryBean创建bean,根据@FeignClient设置相应配置属性
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
validate(attributes);
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
//这里的name依次根据serviceId、name、value获取
String name = getName(attributes);
definition.addPropertyValue("name", name);
String contextId = getContextId(attributes);
definition.addPropertyValue("contextId", contextId);
//这里的className为目标接口类名称
definition.addPropertyValue("type", className);
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
//如果多个@FeignClient存在并且name相同,可以设置@FeignClient(value = "car",primary = false)
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);
}
2、FeignContext
feign的一个上下文环境类,根据clientName创建不同的spring ApplicationContext,并从中注册或者获取属于这个clientName的bean,有效的隔离了不同clientName之间的相互影响
public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
public FeignContext() {
super(FeignClientsConfiguration.class, "feign", "feign.client.name");
}
}
FeignContext继承了NamedContextFactory
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
implements DisposableBean, ApplicationContextAware {
//多个child context的集合,相互间隔离,可以根据key获取相应的上下文环境
private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
//同上,这里可以存储多个隔离的配置类,根据key获取相应的配置类
private Map<String, C> configurations = new ConcurrentHashMap<>();
//根据name从contexts中获取相应的context,并且从中取出bean
public <T> Map<String, T> getInstances(String name, Class<T> type) {
AnnotationConfigApplicationContext context = getContext(name);
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
type).length > 0) {
return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);
}
return null;
}
//根据name获取context的方法,如果contexts中没有相应的context,创建一个
protected AnnotationConfigApplicationContext getContext(String name) {
if (!this.contexts.containsKey(name)) {
synchronized (this.contexts) {
if (!this.contexts.containsKey(name)) {
this.contexts.put(name, createContext(name));
}
}
}
return this.contexts.get(name);
}
//其它方法 略
}
在FeignAutoConfiguration中,springCloud注入了FeignContext
@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {
//FeignClientsRegistrar类中动态注入的FeignClientSpecification,在这里可以获取到
//FeignClientSpecification中包装了@FeignClient或@EnableFeignClients的配置类
//详细看上文中的(1、扫描注入FeignClient注解接口)
@Autowired(required = false)
private List<FeignClientSpecification> configurations = new ArrayList<>();
//这里注入FeignContext
@Bean
public FeignContext feignContext() {
FeignContext context = new FeignContext();
context.setConfigurations(this.configurations);
return context;
}
//省略不重要的代码
}
3、Feign.Builder
Feign用到了建造者模式,所以有一个Builder类负责设置参数以及构建目标类
public static class Builder {
private final List<RequestInterceptor> requestInterceptors =
new ArrayList<RequestInterceptor>();
//设置feign日志级别
private Logger.Level logLevel = Logger.Level.NONE;
//解析目标接口的注解 springCloud默认使用SpringMvcContract
private Contract contract = new Contract.Default();
//http请求类,springCloud默认使用LoadBalancerFeignClient
private Client client = new Client.Default(null, null);
//重试策略类
private Retryer retryer = new Retryer.Default();
//日志类,springCloud默认使用Slf4jLogger
private Logger logger = new NoOpLogger();
//对传输的内容进行编码,springCloud默认使用SpringEncoder
private Encoder encoder = new Encoder.Default();
//对返回的内容进行解码,springCloud默认使用SpringDecoder
private Decoder decoder = new Decoder.Default();
//将object对象转换成map的处理类
private QueryMapEncoder queryMapEncoder = new QueryMapEncoder.Default();
//对失败的http请求进行解码
private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
//http请求参数类,包含connectTimeoutMillis、readTimeoutMillis、是否处理重定向
private Options options = new Options();
//生成InvocationHandler处理类
//Feign通过这种方式加入了hytrix的熔断功能,详细看feign.hystrix.HystrixFeign.Builder#build
private InvocationHandlerFactory invocationHandlerFactory =
new InvocationHandlerFactory.Default();
//是否解码404结果
private boolean decode404;
//是否在发起请求后关闭本次链接
private boolean closeAfterDecode = true;
private ExceptionPropagationPolicy propagationPolicy = NONE;
public <T> T target(Class<T> apiType, String url) {
return target(new HardCodedTarget<T>(apiType, url));
}
//使用反射创建目标接口的实现类
public <T> T target(Target<T> target) {
return build().newInstance(target);
}
//创建了ParseHandlersByName、SynchronousMethodHandler.Factory 并且用ReflectiveFeign进行包装
//ParseHandlersByName 负责调用Contract类解析接口方法以及注解、调用SynchronousMethodHandler.Factory将接口方法包装成MethodHandler进行内部处理
//SynchronousMethodHandler 实现MethodHandler接口,对目标接口方法进行拦截,实现具体的http远程请求
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);
}
//******************下面都是配置操作***********************//
public Builder logLevel(Logger.Level logLevel) {
this.logLevel = logLevel;
return this;
}
public Builder contract(Contract contract) {
this.contract = contract;
return this;
}
public Builder client(Client client) {
this.client = client;
return this;
}
public Builder retryer(Retryer retryer) {
this.retryer = retryer;
return this;
}
public Builder logger(Logger logger) {
this.logger = logger;
return this;
}
public Builder encoder(Encoder encoder) {
this.encoder = encoder;
return this;
}
public Builder decoder(Decoder decoder) {
this.decoder = decoder;
return this;
}
public Builder queryMapEncoder(QueryMapEncoder queryMapEncoder) {
this.queryMapEncoder = queryMapEncoder;
return this;
}
public Builder mapAndDecode(ResponseMapper mapper, Decoder decoder) {
this.decoder = new ResponseMappingDecoder(mapper, decoder);
return this;
}
public Builder decode404() {
this.decode404 = true;
return this;
}
public Builder errorDecoder(ErrorDecoder errorDecoder) {
this.errorDecoder = errorDecoder;
return this;
}
public Builder options(Options options) {
this.options = options;
return this;
}
public Builder requestInterceptor(RequestInterceptor requestInterceptor) {
this.requestInterceptors.add(requestInterceptor);
return this;
}
public Builder requestInterceptors(Iterable<RequestInterceptor> requestInterceptors) {
this.requestInterceptors.clear();
for (RequestInterceptor requestInterceptor : requestInterceptors) {
this.requestInterceptors.add(requestInterceptor);
}
return this;
}
public Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
this.invocationHandlerFactory = invocationHandlerFactory;
return this;
}
public Builder doNotCloseAfterDecode() {
this.closeAfterDecode = false;
return this;
}
public Builder exceptionPropagationPolicy(ExceptionPropagationPolicy propagationPolicy) {
this.propagationPolicy = propagationPolicy;
return this;
}
}
4、Client
负责发送http请求的接口类,实现类需要遵守线程安全
public interface Client {
//执行http请求,返回Response
Response execute(Request request, Options options) throws IOException;
}
feign支持okhttp、httpclient,
默认情况下使用的java的 java.net.HttpURLConnection,并且没有连接池,性能较低
在FeignRibbonClientAutoConfiguration中引入了HttpClientFeignLoadBalancedConfiguration.class、OkHttpFeignLoadBalancedConfiguration.class、
DefaultFeignLoadBalancedConfiguration.class
分别提供支持httpclient、okhttp、HttpURLConnection的Client.class
@ConditionalOnClass({ ILoadBalancer.class, Feign.class })
@Configuration
@AutoConfigureBefore(FeignAutoConfiguration.class)
@EnableConfigurationProperties({ FeignHttpClientProperties.class })
@Import({ HttpClientFeignLoadBalancedConfiguration.class, //httpclient支持
OkHttpFeignLoadBalancedConfiguration.class, //okhttp支持
DefaultFeignLoadBalancedConfiguration.class }) //HttpURLConnection
public class FeignRibbonClientAutoConfiguration {
//略
}
HttpClientFeignLoadBalancedConfiguration.class
@Bean
@ConditionalOnProperty(value = "feign.compression.response.enabled", havingValue = "false", matchIfMissing = true)
public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory, HttpClientConnectionManager httpClientConnectionManager,
FeignHttpClientProperties httpClientProperties) {
//创建CloseableHttpClient对象
this.httpClient = createClient(httpClientFactory.createBuilder(), httpClientConnectionManager, httpClientProperties);
return this.httpClient;
}
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory, HttpClient httpClient) {
//将上面创建的CloseableHttpClient对象设置到ApacheHttpClient中
ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
}
OkHttpFeignLoadBalancedConfiguration.class
@Bean
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory,
ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
Boolean followRedirects = httpClientProperties.isFollowRedirects();
Integer connectTimeout = httpClientProperties.getConnectionTimeout();
//创建okhttp3.OkHttpClient对象
this.okHttpClient = httpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation()).
connectTimeout(connectTimeout, TimeUnit.MILLISECONDS).
followRedirects(followRedirects).
connectionPool(connectionPool).build();
return this.okHttpClient;
}
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory, okhttp3.OkHttpClient okHttpClient) {
OkHttpClient delegate = new OkHttpClient(okHttpClient);
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
}
DefaultFeignLoadBalancedConfiguration.class
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
//使用feign默认的client Client.Default
return new LoadBalancerFeignClient(new Client.Default(null, null),
cachingFactory, clientFactory);
}
启用httpclient
<!--pom.xml-->
<!--这里的version要和feign-core保持一致-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>10.1.0</version>
</dependency>
启用okhttp
<!--pom.xml-->
<!--这里的version要和feign-core保持一致-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>10.1.0</version>
</dependency>
##禁用httpclient
feign.httpclient.enabled=false
##启用okhttp
feign.okhttp.enabled=true
5、FeignClientFactoryBean 动态代理
在第一部分(1、扫描注入FeignClient注解接口) 中讲到在FeignClientsRegistrar实现动态注入,将目标接口类包装成FeignClientFactoryBean
FeignClientFactoryBean实现了FactoryBean接口,也就是说FeignClientFactoryBean是一个bean工厂,通过调用getObject方法提供目标接口的实现类
//请求方通过@Autowired获取目标接口的实现类,实际是调用FeignClientFactoryBean.getObject()
@Autowired
CarClient carClient;
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
ApplicationContextAware {
@Override
public Object getObject() throws Exception {
return getTarget();
}
}
//基于java的面向接口的动态代理方式生成目标接口的实现类
<T> T getTarget() {
//获取Feign的上下文环境,详细看上文(2、FeignContext)
FeignContext context = applicationContext.getBean(FeignContext.class);
//根据上下文环境构建Builder类,填充参数配置
Feign.Builder builder = feign(context);
//这里会对url进行构建,针对上文的例子@FeignClient("car"),url会构建成http://car
if (!StringUtils.hasText(this.url)) {
if (!this.name.startsWith("http")) {
url = "http://" + this.name;
}
else {
url = this.name;
}
url += cleanPath();
return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type,
this.name, url));
}
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
String url = this.url + cleanPath();
//在当前上下文环境中获取Client类型实例,如果用到了ribbon,这里的Client会获取到LoadBalancerFeignClient
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();
}
builder.client(client);
}
//如果引入了hytrix,这里会获取到HystrixTargeter,主要逻辑
//1、定义HystrixCommandKey(CarClient#getCarNoQuery(String))、HystrixCommandGroupKey(car)
//2、对fallback、fallbackFactory进行处理
//3、在builder中加入InvocationHandlerFactory工厂创建HystrixInvocationHandler,在目标接口调用时加入hytrix的熔断功能
//4、最终调用ReflectiveFeign.newInstance(Target<T> target)生成实现类
Targeter targeter = get(context, Targeter.class);
return (T) targeter.target(this, builder, context, new HardCodedTarget<>(
this.type, this.name, url));
}
ReflectiveFeign继承了Feign, 通过builder创建,主要逻辑是对目标接口方法进行解析包装,加入拦截器,最终生成实现类
@SuppressWarnings("unchecked")
@Override
public <T> T newInstance(Target<T> target) {
//这里的targetToHandlersByName就是ParseHandlersByName类,具体看(3、Feign.Builder)
//关键点1
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
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;
//对接口中的default方法进行处理
} 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)));
}
}
//如果引入了hytrix,这里会创建HystrixInvocationHandler,在这里加入熔断
//关键点2
InvocationHandler handler = factory.create(target, methodToHandler);
//java基于接口的动态代理,当方法被调用时,转发给handler进行处理
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
在上述代码中有几个关键的地方
1、ParseHandlersByName处理目标类,最终将目标类的方法包装成MethodHandler
//feign.ReflectiveFeign.ParseHandlersByName.java
public Map<String, MethodHandler> apply(Target key) {
//Contract协议,对目标类方法上的注解进行解析,包装成MethodMetadata
List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
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);
}
//这里是SynchronousMethodHandler.Factory,最终将方法包装成SynchronousMethodHandler
//在这个方法内部实现了request包装、encode编码、请求拦截、调用client做http请求、对返回的response做decoder解码等
result.put(md.configKey(),
factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
}
return result;
}
2、HystrixInvocationHandler对代理方法调用的处理
final class HystrixInvocationHandler implements InvocationHandler {
private final Target<?> target;
private final Map<Method, MethodHandler> dispatch;
private final FallbackFactory<?> fallbackFactory; // Nullable
private final Map<Method, Method> fallbackMethodMap;
private final Map<Method, Setter> setterMethodMap;
HystrixInvocationHandler(Target<?> target, Map<Method, MethodHandler> dispatch,
SetterFactory setterFactory, FallbackFactory<?> fallbackFactory) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch");
this.fallbackFactory = fallbackFactory;
this.fallbackMethodMap = toFallbackMethod(dispatch);
this.setterMethodMap = toSetters(setterFactory, target, dispatch.keySet());
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
// early exit if the invoked method is from java.lang.Object
// code is the same as ReflectiveFeign.FeignInvocationHandler
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();
}
//在这里加入了hystrix熔断功能
HystrixCommand<Object> hystrixCommand =
new HystrixCommand<Object>(setterMethodMap.get(method)) {
@Override
protected Object run() throws Exception {
try {
//这里实际调用了SynchronousMethodHandler.invoke
return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
} catch (Exception e) {
throw e;
} catch (Throwable t) {
throw (Error) t;
}
}
@Override
protected Object getFallback() {
if (fallbackFactory == null) {
return super.getFallback();
}
try {
Object fallback = fallbackFactory.create(getExecutionException());
Object result = fallbackMethodMap.get(method).invoke(fallback, args);
if (isReturnsHystrixCommand(method)) {
return ((HystrixCommand) result).execute();
} else if (isReturnsObservable(method)) {
// Create a cold Observable
return ((Observable) result).toBlocking().first();
} else if (isReturnsSingle(method)) {
// Create a cold Observable as a Single
return ((Single) result).toObservable().toBlocking().first();
} else if (isReturnsCompletable(method)) {
((Completable) result).await();
return null;
} else {
return result;
}
} catch (IllegalAccessException e) {
// shouldn't happen as method is public due to being an interface
throw new AssertionError(e);
} catch (InvocationTargetException e) {
// Exceptions on fallback are tossed by Hystrix
throw new AssertionError(e.getCause());
}
}
};
if (Util.isDefault(method)) {
return hystrixCommand.execute();
} else if (isReturnsHystrixCommand(method)) {
return hystrixCommand;
} else if (isReturnsObservable(method)) {
// Create a cold Observable
return hystrixCommand.toObservable();
} else if (isReturnsSingle(method)) {
// Create a cold Observable as a Single
return hystrixCommand.toObservable().toSingle();
} else if (isReturnsCompletable(method)) {
return hystrixCommand.toObservable().toCompletable();
}
return hystrixCommand.execute();
}
}
6、SynchronousMethodHandler
@Override
public Object invoke(Object[] argv) throws Throwable {
//接收方法参数,进行包装
RequestTemplate template = buildTemplateFromArgs.create(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
return executeAndDecode(template);
} 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;
}
}
}
Object executeAndDecode(RequestTemplate template) throws Throwable {
//进一步包装成Request对象
Request request = targetRequest(template);
//根据日志级别打印不同详细程度的日志
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Response response;
long start = System.nanoTime();
try {
//如果引入了ribbon,这里的client的实现类是LoadBalancerFeignClient
//将会对请求服务进行负载算法,选出一个地址,并且调用最终的http请求框架,例如httpClient、okhttp
response = client.execute(request, options);
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throw errorExecuting(request, e);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
boolean shouldClose = true;
try {
if (logLevel != Logger.Level.NONE) {
response =
logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
}
if (Response.class == metadata.returnType()) {
if (response.body() == null) {
return response;
}
if (response.body().length() == null ||
response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose = false;
return response;
}
// Ensure the response body is disconnected
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
return response.toBuilder().body(bodyData).build();
}
if (response.status() >= 200 && response.status() < 300) {
if (void.class == metadata.returnType()) {
return null;
} else {
//对返回的结果进行解码处理,这里默认调用springDecode
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
}
} else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
} else {
throw errorDecoder.decode(metadata.configKey(), response);
}
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
}
throw errorReading(request, response, e);
} finally {
if (shouldClose) {
ensureClosed(response.body());
}
}
}
7、Contract协议
用来解析接口方法、参数以及注解的协议
public interface Contract {
List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType);
}
Contract内部提供了一个抽象类BaseContract,做了一些基础的处理,以及定义了三个抽象方法方便子类进行功能扩展
abstract class BaseContract implements Contract{
//略去多余代码
//对目标class上的注解进行解析
protected abstract void processAnnotationOnClass(MethodMetadata data, Class<?> clz);
//对目标方法上的注解进行解析
protected abstract void processAnnotationOnMethod(MethodMetadata data,
Annotation annotation,
Method method);
//对目标方法的传参上的注解进行解析
protected abstract boolean processAnnotationsOnParameter(MethodMetadata data,
Annotation[] annotations,
int paramIndex);
}
feign基于BaseContract 在Contract内部实现了一个默认的解析协议Default,使用了他自己定义的注解
但是基于学习成本以及大家的使用习惯,springCloud基于BaseContract实现了SpringMvcContract,可以使用部分springMvc的注解,支持@RequestMapping、@PathVariable、@RequestHeader、@RequestParam
如果参数不加注解,默认按照requestBody去处理