优质博文:IT-BLOG-CN
我们这次项目主要从RestTemplate 和 Feign 进行选型分析。
一、Spring Cloud Feign分析
Feign是另外一种客户端负载平衡实现。
我在该模块写了Feign Client的示例代码。
【1】spring-cloud-web-demo-api为服务的sdk模块
【2】spring-cloud-web-demo-service为提供接口服务的模块
【3】spring-cloud-web-demo-client为模拟调用服务的模块
首先在spring-cloud-web-demo-api模块,定义Feign API。spring-cloud-web-demo为spring-cloud-web-demo-service暴露的服务名。
- @FeignClient(value = "spring-cloud-web-demo")
- public interface UserFeign {
- @GetMapping(value = "/user/getUserById", produces = "application/json;charset=utf-8")
- Object getUserById(@RequestParam(value = "id", required = false) Long id);
- //省略
- }
复制代码 然后通过ClientAutoConfiguration主动装配。(client直接引入api包就可以使用,不需要再EnableFeignClients)
- @Configuration
- @EnableFeignClients("net.teaho.demo.spring.cloud.web.api")
- public class ClientAutoConfiguration {
- }
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- net.teaho.demo.spring.cloud.web.api.config.ClientAutoConfiguration
复制代码 在service模块如以往Spring MVC般实现api模块接口即可。
- @RestController
- public class UserController implements UserFeign {
- private static final Logger logger = LoggerFactory.getLogger(UserController.class);
- @Override
- public Object getUserById(Long id) {
- return "{"id":1, "name": "test"}";
- }
- //省略
- }
复制代码 在Client模块,注入bean后直接调用。
- @Component
- @Slf4j
- public class TestService {
- @Autowired
- private RestTemplate restTemplate;
- public Object getOneUser(){
- return userController.getUserById(1L);
- }
- }
复制代码 二、RestTemplate分析
写了具有客户端负载平衡能力的RestTemplate的哀求代码。
类似这样定义:
- @Bean
- @LoadBalanced
- public RestTemplate restTemplate() {
- return new RestTemplate();
- }
复制代码 RestTemplate毕竟是如何使用注册中央实现客户端负载平衡的呢?
实现方式: 就是将上面所说的LoadBalancerInterceptor负载平衡拦截器加到标注了@LoadBalanced的RestTemplate实例中。 LoadBalancerInterceptor拦截器会在执行过程中获取并设置适合的目的哀求实例,重新构造哀求URI。
- // 将配置中标注了@LoadBalanced的RestTemplate注入到这里
- @LoadBalanced
- @Autowired(required = false)
- private List<RestTemplate> restTemplates = Collections.emptyList();
- //将注册的RestTemplateCustomizer(RestTemplate自定义器)集合处理上面的restTemplates集合
- @Bean
- public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
- final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
- return () -> restTemplateCustomizers.ifAvailable(customizers -> {
- for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
- for (RestTemplateCustomizer customizer : customizers) {
- customizer.customize(restTemplate);
- }
- }
- });
- }
复制代码 三、技能选型
最终选择使用OpenFeign,下面说说缘故原由。
和RestTemplate比起来,OpenFeign显得更适合Spring Boot微服务。
Open Feign相当于(HTTP)RPC,相比起RestTemplate,它直接显式将API声明以JAVA接口形式标识出来。 并且因为底层用的动态署理,它还可以(无感知地)更换底层实现。好比,github上就有更换底层逻辑的repo – Open Feign+Dubbo的RPC实现。
通过sdk包的形式,方便了调用,不需要像RestTemplate一样,客户端自行拼接上一串哀求参数。在代码编写上也清晰。
要使用就必须知道OpenFeign是怎么实现的呢?
四、OpenFeign 初始化分析
流程图如下:

看看前面例子里我们引入的OpenFeign的东西
【1】@EnableFeignClients(“net.teaho.demo.spring.cloud.web.api”)
【2】@FeignClient(value = “spring-cloud-web-demo”) 还有主动装配引入的
【3】FeignRibbonClientAutoConfiguration
【4】FeignClientsConfiguration
我们就从这两个注解开始分析源码。
【1】首先看@FeignClient注解。
- //给接口标注成一个REST调用方
- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface FeignClient {
- //服务名,可以带协议前缀,也可以用${property.name}关联一个配置值。
- @AliasFor("name")
- String value() default "";
- @Deprecated
- String serviceId() default "";
- //bean name
- String contextId() default "";
- @AliasFor("value")
- String name() default "";
- /**
- * Sets the <code>@Qualifier</code> value for the feign client.
- */
- String qualifier() default "";
- //直接指定一个地址,比如http://localhost:12345,一般用于调试
- String url() default "";
- boolean decode404() default false;
- /**
- * A custom <code>@Configuration</code> for the feign client. Can contain override
- * <code>@Bean</code> definition for the pieces that make up the client, for instance
- * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
- *
- * @see FeignClientsConfiguration for the defaults
- */
- //可用于覆盖FeignClient默认设置
- Class<?>[] configuration() default {};
- //回滚类,像我的例子中定义的回滚类必须实现UserFeign接口,看https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/single/spring-cloud.html#spring-cloud-feign-hystrix-fallback
- Class<?> fallback() default void.class;
- //如果需要对异常做诊断可用此属性,https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/single/spring-cloud.html#spring-cloud-feign-hystrix-fallback
- Class<?> fallbackFactory() default void.class;
- //路径前缀
- String path() default "";
- //标记bean是否为primary
- boolean primary() default true;
- }
复制代码 【2】接下来重点关注@EnableFeignClients注解是如何扫描FeignClient接口的。
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.TYPE)
- @Documented
- @Import(FeignClientsRegistrar.class)
- public @interface EnableFeignClients {
- //省略
- }
复制代码 嗯,发现没有,就是FeignClientsRegistrar做处理惩罚的。来分析下重点方法registerFeignClients和registerFeignClient
- class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
- ResourceLoaderAware, EnvironmentAware {
- public void registerFeignClients(AnnotationMetadata metadata,
- BeanDefinitionRegistry registry) {
- //classPath扫描器
- ClassPathScanningCandidateComponentProvider scanner = getScanner();
- scanner.setResourceLoader(this.resourceLoader);
- //ClassPathScanningCandidateComponentProvider扫描的basePackage集合
- Set<String> basePackages;
- Map<String, Object> attrs = metadata
- .getAnnotationAttributes(EnableFeignClients.class.getName());
- //扫描器用于扫描标注了@FeignClient类的拦截器
- AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
- FeignClient.class);
- final Class<?>[] clients = attrs == null ? null
- : (Class<?>[]) attrs.get("clients");
- //clients属性为空,以@EnableFeignClients的value、basePackage等为根包扫描
- if (clients == null || clients.length == 0) {
- scanner.addIncludeFilter(annotationTypeFilter);
- basePackages = getBasePackages(metadata);
- }
- //@EnableFeignClients的clients属性不为空,解析clients的类和根包
- else {
- final Set<String> clientClasses = new HashSet<>();
- basePackages = new HashSet<>();
- for (Class<?> clazz : clients) {
- basePackages.add(ClassUtils.getPackageName(clazz));
- clientClasses.add(clazz.getCanonicalName());
- }
- AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
- @Override
- protected boolean match(ClassMetadata metadata) {
- String cleaned = metadata.getClassName().replaceAll("\\$", ".");
- return clientClasses.contains(cleaned);
- }
- };
- scanner.addIncludeFilter(
- new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
- }
- //1.根据basePackage找到目标@FeignClient接口
- //2.检查是否为接口
- //3.将找到的接口注册为FeignClientFactoryBean
- 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());
- String name = getClientName(attributes);
- registerClientConfiguration(registry, name,
- attributes.get("configuration"));
- registerFeignClient(registry, annotationMetadata, attributes);
- }
- }
- }
- }
- private String getClientName(Map<String, Object> client) {
- if (client == null) {
- return null;
- }
- String value = (String) client.get("contextId");
- if (!StringUtils.hasText(value)) {
- value = (String) client.get("value");
- }
- if (!StringUtils.hasText(value)) {
- value = (String) client.get("name");
- }
- if (!StringUtils.hasText(value)) {
- value = (String) client.get("serviceId");
- }
- if (StringUtils.hasText(value)) {
- return value;
- }
- throw new IllegalStateException("Either 'name' or 'value' must be provided in @"
- + FeignClient.class.getSimpleName());
- }
- private void registerFeignClient(BeanDefinitionRegistry registry,
- AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
- String className = annotationMetadata.getClassName();
- BeanDefinitionBuilder definition = BeanDefinitionBuilder
- .genericBeanDefinition(FeignClientFactoryBean.class);
- validate(attributes);
- definition.addPropertyValue("url", getUrl(attributes));
- definition.addPropertyValue("path", getPath(attributes));
- String name = getName(attributes);
- definition.addPropertyValue("name", name);
- String contextId = getContextId(attributes);
- definition.addPropertyValue("contextId", contextId);
- 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
- 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);
- }
- }
复制代码 可以看到最后注册beanDefinition时,我们看到注册了FeignClientFactoryBean这一FactoryBean。 我们看看工厂bean FeignClientFactoryBean是如何构造对象的。
- class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
- ApplicationContextAware {
- //省略
- @Override
- public Object getObject() throws Exception {
- return getTarget();
- }
- <T> T getTarget() {
- //1.获取FeignContext,在FeignAutoConfiguration声明
- FeignContext context = applicationContext.getBean(FeignContext.class);
- //2.构造Feign builder
- Feign.Builder builder = feign(context);
- //3.如果没有设置url参数
- if (!StringUtils.hasText(this.url)) {
- if (!this.name.startsWith("http")) {
- url = "http://" + this.name;
- }
- else {
- url = this.name;
- }
- //4.设置path
- url += cleanPath();
- //5.获取Client(用于执行最终HTTP/HTTPS请求,比如LoadBalancerFeignClient),
- //构造反射实例
- return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type,
- this.name, url));
- }
- //存在url参数,构造非loadBalance的请求实例(target)
- if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
- this.url = "http://" + this.url;
- }
- String url = this.url + cleanPath();
- 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);
- }
- Targeter targeter = get(context, Targeter.class);
- return (T) targeter.target(this, builder, context, new HardCodedTarget<>(
- this.type, this.name, url));
- }
- //在FeignContext中获取一些在FeignClientsConfiguration中声明,Feign需要用到的组件
- protected Feign.Builder feign(FeignContext context) {
- FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
- Logger logger = loggerFactory.create(this.type);
- // @formatter:off
- Feign.Builder builder = get(context, Feign.Builder.class)
- // required values
- .logger(logger)
- .encoder(get(context, Encoder.class))
- .decoder(get(context, Decoder.class))
- .contract(get(context, Contract.class));
- // @formatter:on
- configureFeign(context, builder);
- return builder;
- }
- protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
- HardCodedTarget<T> target) {
- //获取Client
- Client client = getOptional(context, Client.class);
- if (client != null) {
- builder.client(client);
- //从Context获取Targeter,Targeter用于生成最终target实例(对应我的例子是被调用的通过反射生成的UserFeign实例)
- Targeter targeter = get(context, Targeter.class);
- 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?");
- }
- //省略
- }
复制代码 在非调试环境下(即我们没设置url参数), 我们来看看targeter.target(this, builder, context, target)做了什么。
Targeter接口是构造被哀求的署理bean的类。有两个实现类HystrixTargeter、DefaultTargeter。
HystrixTargeter会比默认的多设置一些回滚措施,用到Feign的Contract属性, 我会先从DefaultTargeter说起。
DefaultTargeter会通过Feign.Builder#target(Target target)生成实例。我们来看看代码。
- public abstract class Feign {
- //省略
- public static class Builder {
- private final List<RequestInterceptor> requestInterceptors =
- new ArrayList<RequestInterceptor>();
- private Logger.Level logLevel = Logger.Level.NONE;
- private Contract contract = new Contract.Default();
- private Client client = new Client.Default(null, null);
- private Retryer retryer = new Retryer.Default();
- private Logger logger = new NoOpLogger();
- private Encoder encoder = new Encoder.Default();
- private Decoder decoder = new Decoder.Default();
- private QueryMapEncoder queryMapEncoder = new QueryMapEncoder.Default();
- private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
- private Options options = new Options();
- private InvocationHandlerFactory invocationHandlerFactory =
- new InvocationHandlerFactory.Default();
- 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);
- }
- //默认实现就是创建一个ReflectiveFeign实例
- 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);
- }
- }
- //省略
- }
复制代码 在解读ReflectiveFeign前介绍几个概念:
1、InvocationHandlerFactory 是控制反射方法分发的接口,create方法返回InvocationHandler。
2、InvocationHandlerFactory.MethodHandler 最终将对署理类方法调用转换成HTTP哀求的地方,请看实现类SynchronousMethodHandler
3、InvocationHandlerFactory.Default 默认实现,作为构造参数传入ReflectiveFeign,create方法创建的是new ReflectiveFeign.FeignInvocationHandler(target, dispatch)。
4、ReflectiveFeign.ParseHandlersByName 作为构造参数传入ReflectiveFeign,核心方法apply(Target key)先将标注了@FeignClient的接口的方法解析出待处理惩罚的元数据List, 然后创建出方法名和方法处理惩罚器的map映射Map<String, MethodHandler>String是方法名,方法处理惩罚器通过SynchronousMethodHandler.Factory#create创建。
5、FeignInvocationHandler 为处理惩罚一样平常方法的处理惩罚器
6、DefaultMethodHandler 为处理惩罚接口默认方法的处理惩罚器
有了以上介绍,接下来简朴分析ReflectiveFeign的newInstance方法。
- public class ReflectiveFeign extends Feign {
- private final ParseHandlersByName targetToHandlersByName;
- private final InvocationHandlerFactory factory;
- private final QueryMapEncoder queryMapEncoder;
- ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory,
- QueryMapEncoder queryMapEncoder) {
- this.targetToHandlersByName = targetToHandlersByName;
- this.factory = factory;
- this.queryMapEncoder = queryMapEncoder;
- }
- ..
- /**
- * creates an api binding to the {@code target}. As this invokes reflection, care should be taken
- * to cache the result.
- */
- @SuppressWarnings("unchecked")
- @Override
- public <T> T newInstance(Target<T> target) {
- //创建方法名和方法处理器的map映射
- 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;
- //判断是否为接口的默认方法,DefaultMethodHandler的处理逻辑是直接调用会原接口的default方法
- } else if (Util.isDefault(method)) {
- DefaultMethodHandler handler = new DefaultMethodHandler(method);
- defaultMethodHandlers.add(handler);
- methodToHandler.put(method, handler);
- } else {
- //方法处理map
- methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
- }
- }
- InvocationHandler handler = factory.create(target, methodToHandler);
- //jdk动态代理创建对象
- T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
- new Class<?>[] {target.type()}, handler);
- //将默认方法处理器也绑定到代理对象上
- for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
- defaultMethodHandler.bindTo(proxy);
- }
- return proxy;
- }
- static class FeignInvocationHandler implements InvocationHandler {
- private final Target target;
- private final Map<Method, MethodHandler> dispatch;
- //省略
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- //自定义的equals、hashCode和toString的处理
- 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();
- }
- //分发调用到对应方法的InvocationHandlerFactory.MethodHandler
- return dispatch.get(method).invoke(args);
- }
- //省略
- }
复制代码 初始化完成。
五、OpenFeign 执行分析
上图是OpenFeign构造的署理对象被调用时的时序图。
1、署理对象被执行
2、找到对应SynchronousMethodHandler进行方法调用。
3、构造RequestTemplate
4、LoadBalancerFeignClient执行负载哀求
5、FeignLoadBalancer通过ILoadBalancer选择合适Server,通过Server重组URI,通过RibbonRequest持有的Client执行实际HTTP哀求包装成Response。
6、SynchronousMethodHandler通过Decoder将哀求响应用Decoder解码成最终效果。
下面介绍执行过程中涉及到源码中的部分组件。
1、RequestTemplate 是一个HTTP哀求内容的抽象。
2、RequestTemplate.Factory 将方法参数解析成RequestTemplate。
3、Retryer 我在上面的时序图没有标注出来,实际上它在SynchronousMethodHandler的执行中控制重试逻辑。
4、RequestInterceptor 在SynchronousMethodHandler发起执行中,会使用该拦截器对RequestTemplate进行处理惩罚。这是一个拓展点。
5、Logger 执行哀求时打日记(在debug时打)。默认为Logger.Level.NONE即不打日记,可以增加bean覆盖。
- Logger.Level.NONE 不打印信息
- Logger.Level.BASIC 打印哀求url和响应码。
- Logger.Level.HEADERS 打印BASIC信息外加header信息
- Logger.Level.FULL 打印所有
6、LoadBalancerFeignClient Client接口的实现类,是具有负载平衡能力的Client。Client接口为执行HTTP的接口,Client.Default是最终发出HTTP哀求的类。
7、FeignLoadBalancer FeignLoadBalancer通过ILoadBalancer选择合适Server,通过Server重组URI,通过RibbonRequest持有的Client执行实际HTTP哀求包装成Response。
8、LoadBalancerCommand ribbon的rxJava实现,执行负载流程逻辑的组件。
9、ILoadBalancer ribbon的负载平衡器抽象。
熔断: 在FeignClientsConfiguration中, 当配置了feign.hystrix.enabled,Feign Builder使用HystrixFeign.builder()。
以是build的时候新建HystrixInvocationHandler和HystrixDelegatingContract实例。
- Feign build(final FallbackFactory<?> nullableFallbackFactory) {
- super.invocationHandlerFactory(new InvocationHandlerFactory() {
- @Override
- public InvocationHandler create(Target target,
- Map<Method, MethodHandler> dispatch) {
- return new HystrixInvocationHandler(target, dispatch, setterFactory,
- nullableFallbackFactory);
- }
- });
- super.contract(new HystrixDelegatingContract(contract));
- return super.build();
- }
复制代码 来看看HystrixInvocationHandler的hystrix调用代码
- final class HystrixInvocationHandler implements InvocationHandler {
- //省略
- @Override
- public Object invoke(final Object proxy, final Method method, final Object[] args)
- throws Throwable {
- //省略
- HystrixCommand<Object> hystrixCommand =
- new HystrixCommand<Object>(setterMethodMap.get(method)) {
- //实际执行
- @Override
- protected Object run() throws Exception {
- try {
- 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 {
- //用配置的fallbackFactory创建fallback实例
- Object fallback = fallbackFactory.create(getExecutionException());
- Object result = fallbackMethodMap.get(method).invoke(fallback, args);
- //根据fallback对象的returntype解析包装内的结果返回
- 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());
- }
- }
- };
- //根据方法的return去返回结果
- 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();
- }
- //省略
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |