最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入分析Spring Cloud 負載均衡器架構選型

 更新時間:2024年12月26日 14:31:31   作者:程序猿進階  
文章詳細介紹了OpenFeign的初始化和執(zhí)行流程,包括FeignClient注解、FeignClientsRegistrar類、FeignClientFactoryBean工廠類、Targeter接口及其實現(xiàn)等,感興趣的朋友一起看看吧

我們這次項目主要從RestTemplate 和 Feign 進行選型分析。

一、Spring Cloud Feign分析

Feign是另外一種客戶端負載均衡實現(xiàn)。

我在該模塊寫了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般實現(xiàn)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究竟是如何利用注冊中心實現(xiàn)客戶端負載均衡的呢?

實現(xiàn)方式: 就是將上面所說的LoadBalancerInterceptor負載均衡攔截器加到標注了@LoadBalanced的RestTemplate實例中。 LoadBalancerInterceptor攔截器會在執(zhí)行過程中獲取并設置適合的目標請求實例,重新構造請求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接口形式標識出來。 并且因為底層用的動態(tài)代理,它還可以(無感知地)替換底層實現(xiàn)。比如,github上就有替換底層邏輯的repo – Open Feign+Dubbo的RPC實現(xiàn)。

通過sdk包的形式,方便了調用,不需要像RestTemplate一樣,客戶端自行拼接上一串請求參數(shù)。在代碼編寫上也清晰。

要使用就必須知道OpenFeign是怎么實現(xiàn)的呢?

四、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 {
    //服務名,可以帶協(xié)議前綴,也可以用${property.name}關聯(lián)一個配置值。
    @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 {};
    //回滾類,像我的例子中定義的回滾類必須實現(xiàn)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 {
    //省略
}

嗯,發(fā)現(xiàn)沒有,就是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.根據(jù)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參數(shù)
        if (!StringUtils.hasText(this.url)) {
            if (!this.name.startsWith("http")) {
                url = "http://" + this.name;
            }
            else {
                url = this.name;
            }
            //4.設置path
            url += cleanPath();
            //5.獲取Client(用于執(zhí)行最終HTTP/HTTPS請求,比如LoadBalancerFeignClient),
            //構造反射實例
            return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type,
                    this.name, url));
        }
        //存在url參數(shù),構造非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中聲明,F(xiàn)eign需要用到的組件
    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參數(shù)), 我們來看看targeter.target(this, builder, context, target)做了什么。

Targeter接口是構造被請求的代理bean的類。有兩個實現(xiàn)類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);
    }
    //默認實現(xiàn)就是創(chuàng)建一個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 是控制反射方法分發(fā)的接口,create方法返回InvocationHandler。
2、InvocationHandlerFactory.MethodHandler 最終將對代理類方法調用轉換成HTTP請求的地方,請看實現(xiàn)類SynchronousMethodHandler
3、InvocationHandlerFactory.Default 默認實現(xiàn),作為構造參數(shù)傳入ReflectiveFeign,create方法創(chuàng)建的是new ReflectiveFeign.FeignInvocationHandler(target, dispatch)。
4、ReflectiveFeign.ParseHandlersByName 作為構造參數(shù)傳入ReflectiveFeign,核心方法apply(Target key)先將標注了@FeignClient的接口的方法解析出待處理的元數(shù)據(jù)List, 然后創(chuàng)建出方法名和方法處理器的map映射Map<String, MethodHandler>String是方法名,方法處理器通過SynchronousMethodHandler.Factory#create創(chuàng)建。
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) {
    //創(chuàng)建方法名和方法處理器的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ài)代理創(chuàng)建對象
    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();
      }
      //分發(fā)調用到對應方法的InvocationHandlerFactory.MethodHandler
      return dispatch.get(method).invoke(args);
    }
    //省略
}

初始化完成。

五、OpenFeign 執(zhí)行分析

上圖是OpenFeign構造的代理對象被調用時的時序圖。
1、代理對象被執(zhí)行
2、找到對應SynchronousMethodHandler進行方法調用。
3、構造RequestTemplate
4、LoadBalancerFeignClient執(zhí)行負載請求
5、FeignLoadBalancer通過ILoadBalancer選擇合適Server,通過Server重組URI,通過RibbonRequest持有的Client執(zhí)行實際HTTP請求包裝成Response。
6、SynchronousMethodHandler通過Decoder將請求響應用Decoder解碼成最終結果。

下面介紹執(zhí)行過程中涉及到源碼中的部分組件。
1、RequestTemplate 是一個HTTP請求內容的抽象。
2、RequestTemplate.Factory 將方法參數(shù)解析成RequestTemplate。
3、Retryer 我在上面的時序圖沒有標注出來,實際上它在SynchronousMethodHandler的執(zhí)行中控制重試邏輯。
4、RequestInterceptor 在SynchronousMethodHandler發(fā)起執(zhí)行中,會使用該攔截器對RequestTemplate進行處理。這是一個拓展點。
5、Logger 執(zhí)行請求時打日志(在debug時打)。默認為Logger.Level.NONE即不打日志,可以增加bean覆蓋。

  • Logger.Level.NONE 不打印信息
  • Logger.Level.BASIC 打印請求url和響應碼。
  • Logger.Level.HEADERS 打印BASIC信息外加header信息
  • Logger.Level.FULL 打印所有

6、LoadBalancerFeignClient Client接口的實現(xiàn)類,是具有負載均衡能力的Client。Client接口為執(zhí)行HTTP的接口,Client.Default是最終發(fā)出HTTP請求的類。

7、FeignLoadBalancer FeignLoadBalancer通過ILoadBalancer選擇合適Server,通過Server重組URI,通過RibbonRequest持有的Client執(zhí)行實際HTTP請求包裝成Response。
8、LoadBalancerCommand ribbon的rxJava實現(xiàn),執(zhí)行負載流程邏輯的組件。
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)) {
          //實際執(zhí)行
          @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創(chuàng)建fallback實例
              Object fallback = fallbackFactory.create(getExecutionException());
              Object result = fallbackMethodMap.get(method).invoke(fallback, args);
              //根據(jù)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());
            }
          }
        };
    //根據(jù)方法的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();
  }
   //省略
}

到此這篇關于Spring Cloud 負載均衡器架構選型的文章就介紹到這了,更多相關Spring Cloud 負載均衡內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • spring mvc url匹配禁用后綴訪問操作

    spring mvc url匹配禁用后綴訪問操作

    這篇文章主要介紹了spring mvc url匹配禁用后綴訪問操作,具有很好的參考價值,希望對大家有所幫助。以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家
    2021-07-07
  • SpringBoot如何通過Feign調用傳遞Header中參數(shù)

    SpringBoot如何通過Feign調用傳遞Header中參數(shù)

    這篇文章主要介紹了SpringBoot通過Feign調用傳遞Header中參數(shù),本文給大家分享兩種解決方案給大家詳細講解,需要的朋友可以參考下
    2023-04-04
  • 如何通過XML方式配置AOP過程解析

    如何通過XML方式配置AOP過程解析

    這篇文章主要介紹了如何通過XML方式配置AOP過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • 簡單聊聊工作中常用的Java?Lambda表達式

    簡單聊聊工作中常用的Java?Lambda表達式

    日常開發(fā)中,我們很多時候需要用到Java?8的Lambda表達式,它允許把函數(shù)作為一個方法的參數(shù),讓我們的代碼更優(yōu)雅、更簡潔。所以整理了一波工作中常用的Lambda表達式??赐暌欢〞袔椭?/div> 2022-11-11
  • SpringBoot+EasyPoi實現(xiàn)excel導出功能

    SpringBoot+EasyPoi實現(xiàn)excel導出功能

    最新小編遇到這樣一個需求,根據(jù)檢索條件查詢列表并將結果導出到excel,實現(xiàn)過程也非常簡單,感興趣的朋友跟隨小編一起看看吧
    2021-09-09
  • Springboot 自定義校驗代碼實例

    Springboot 自定義校驗代碼實例

    這篇文章主要介紹了Springboot 自定義校驗代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • Java線程中斷interrupt的常用方法

    Java線程中斷interrupt的常用方法

    本文主要介紹了Java線程中斷interrupt的常用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • Java調用DeepSeek實現(xiàn)多輪對話功能

    Java調用DeepSeek實現(xiàn)多輪對話功能

    對于廣大Java開發(fā)者而言,DeepSeek這一先進的人工智能技術,猶如一把鑰匙,為我們打開了提升開發(fā)效率與創(chuàng)新能力的新大門,本文給大家介紹了Java調用DeepSeek實現(xiàn)多輪對話功能,需要的朋友可以參考下
    2025-03-03
  • Java刪除ArrayList中的重復元素的兩種方法

    Java刪除ArrayList中的重復元素的兩種方法

    在Java編程中,ArrayList是一種常用的集合類,它允許我們存儲一組元素,在某些情況下,我們可能需要移除其中重復的元素,只保留唯一的元素,下面介紹兩種常見的刪除ArrayList中重復元素的方法,需要的朋友可以參考下
    2024-12-12
  • Java泛型初學者之上、下界通配符的深入理解

    Java泛型初學者之上、下界通配符的深入理解

    這篇文章主要給大家介紹了關于Java泛型初學者之上、下界通配符的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者實用Java具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-12-12

最新評論

海伦市| 北流市| 泰来县| 九江市| 太仓市| 高州市| 从化市| 龙井市| 琼中| 德兴市| 桐城市| 通道| 辽宁省| 新余市| 罗源县| 板桥市| 霍山县| 新昌县| 静安区| 武平县| 葫芦岛市| 漳浦县| 宣武区| 公安县| 宜宾县| 汕尾市| 阿鲁科尔沁旗| 温州市| 句容市| 连山| 丹东市| 湘乡市| 南通市| 天祝| 都匀市| 陈巴尔虎旗| 镇安县| 南昌市| 钟山县| 云霄县| 蒙山县|