SpringCloudOpenFeign的详解

1. SpringCloud OpenFeign的特性

1. 概念

  1. Feign是一个声明式web Rest服务客户端。它使编写web服务客户端更容易
  2. 要使用Feign,请创建一个接口并对其使用注解进行标注
  3. 它具有可插入注释支持,包括Feign注释和JAX-RS注释
  4. Feign还支持可插拔编码器和解码器
  5. Spring Cloud增加了对Spring MVC注释的支持,并支持使用与Spring Web中默认使用的HttpMessageConverters相同的HttpMessageConverters
  6. Spring Cloud集成了Eureka、Spring Cloud CircuitBreaker以及Spring Cloud LoadBalancer,在使用Feign时提供负载均衡的http客户端

2. 简单使用

  1. 引入依赖

    <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
  2. 启动类

    @SpringBootApplication
    @EnableFeignClients
    public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
    }
  3. 标注Feign客户端

    @FeignClient("stores")
    public interface StoreClient {@RequestMapping(method = RequestMethod.GET, value = "/stores")List<Store> getStores();@GetMapping("/stores")Page<Store> getStores(Pageable pageable);@PostMapping(value = "/stores/{storeId}", consumes = "application/json")Store update(@PathVariable("storeId") Long storeId, Store store);@DeleteMapping("/stores/{storeId:\\d+}")void delete(@PathVariable Long storeId);
    }
    
  4. 案例总结

    1. 在@FeignClient注释中,字符串值(上面的“stores”)是一个任意的客户端名称,用于创建Spring Cloud LoadBalancer客户端

    2. 还可以使用URL属性(URL的绝对值或直接写主机名)指定请求的url路径

      1. 之前的版本,FeignClient的url属性可以单独使用,不需要再写name属性

      2. 现在,就算使用url属性,仍然需要name属性]

        @FeignClient(name = "${feign.name}", url = "${feign.url}")
        public interface StoreClient {
        }
        
    3. Spring容器中bean的名称是接口的完全限定名称。要指定自己的别名值,可以使用@FeignClient注释的qualifiers值

    4. 上面的负载均衡客户端将需要发现“stores”服务的物理地址

      1. 如果您的应用程序是Eureka客户端,那么它将在Eureka服务注册表中解析服务
      2. 如果不想使用Eureka,可以使用SimpleDiscoveryClient在外部配置中配置服务器列表
      3. 或者使用其他的客户端(例如Nacos,Consul),提供对应服务的DiscoveryClient实现该实现提供指定服务的实例
    5. Spring Cloud OpenFeign支持Spring Cloud LoadBalancer阻塞模式的所有可用特性

    6. @EnableFeignClients默认扫描标注类的包下的FeignCLient接口,如果想指定包路径或者指定FeignClient接口,可以使用

      1. @EnableFeignClients(basePackages = "com.example.clients")
      2. @EnableFeignClients(clients = InventoryServiceFeignClient.class)
    7. 默认情况下,Feign客户端是立即加载的,它还可以支持AOT,如果不想他们立即加载,可以设置为懒加载

      1. spring.cloud.openfeign.lazy-attributes-resolution=true

3. 覆盖Feign的默认配置

  1. Spring Cloud的Feign支持的一个中心概念: 命名(具名)客户端
  2. 每个Feign客户端都是组件集成的一部分,这些组件协同工作来按需请求远程服务器,我们可以使用@FeignClient注解为客户端提供一个名称
  3. Spring Cloud根据需要使用FeignClientsConfiguration配置类为每个命名的客户端创建一个独立的新的ApplicationContext。包含feign.Decoder,feign.Encoder,feign.Contract核心组件,这些都是在FeignClientsConfiguration配置类中提供的默认组件
    1. 我们可以通过使用@FeignClient注解的contextId属性来覆盖该Feign客户端的名称(name属性)
  4. Spring Cloud允许我们通过使用@FeignClient声明额外的配置来完全控制FeignClient,覆盖FeignClientsConfiguration配置的组件实例,使用@FeignClient的configuration属性
    1. 注意: 在这种使用configuration属性情况下FooConfiguration不需要加@Configuration注解
    2. 因为如果它是一个Bean,那么所有的FeignClient默认配置类FeignClientsConfiguration的对应组件配置就都不会生效,因为它默认配置类都标注了@ConditionalOnMissingBean,因为该Bean存在所有FeignClient独立的ApplicationContext的父容器中,从而使用这个配置类中配置的组件,这样它就覆盖了默认的配置
    3. 无论如何,它最终都会通过AnnotationConfigRegistry#register(applicatioContext)进行注册,最终扫描该配置类,类似与启动类的配置类效果,最终在调用FeignClient独立的ApplicationContext的refresh方法时进行解析该配置
    4. 因此,需要注意,该配置类最好不加@Configuration,这样的话,该配置仅为了指定的FeignClient生效,否则将覆盖所有FeignClient的默认配置,除非自己确实需要这样去做
@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
}
public class FooConfiguration{// 等等其他组件覆盖FeignClientsConfiguration的默认配置@Beanpublic Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider,ObjectProvider<HttpMessageConverterCustomizer> customizers) {return springEncoder(formWriterProvider, encoderProperties, customizers);}
}

4. Feign提供和支持的Bean组件

1. SpringCloud默认提供下面这些Bean

  1. Decoder
    1. beanName: feignDecoder
    2. beanType: ResponseEntityDecoder
  2. Encoder
    1. beanName: feignEncoder
    2. beanType: SpringEncoder
  3. Logger
    1. beanName: feignLogger
    2. beanType: Slf4jLogger
  4. 链路追踪相关的增强器
    1. MicrometerObservationCapability
    2. MicrometerCapability
  5. 缓存的增强器
    1. CachingCapability
  6. Contract
    1. beanName: feignContract
    2. beanType: SpringMvcContract
  7. Feign.Builder
    1. beanName: feignBuilder
    2. beanType: FeignCircuitBreaker.Builder
  8. Client (重要)
    1. beanName: feignClient
    2. beanType: FeignBlockingLoadBalancerClient(如果存在Spring Cloud LoadBalancer依赖),否则使用默认的 Client.Default,使用HttpURLConnection处理
    3. 此外,可以修改默认的Client,因为默认的处理请求的效率很低
      1. 开启okhttp:
        1. spring.cloud.openfeign.okhttp.enabled: true
      2. 开启http2client
        1. spring.cloud.openfeign.http2client.enabled: true
      3. 开启httpclient5
        1. spring.cloud.openfeign.httpclient.hc5.enabled: true
      4. 注意: 都需要导入对应的依赖才行

2. Feign没有提供默认的Bean,但是会从容器中加载的Bean

  1. Logger.Level 日志级别
  2. Retryer 重试机制,默认禁止重试
  3. ErrorDecoder 异常解码器,解析之后可以得到一个异常信息
  4. Request.Options 请求参数配置信息
  5. Collection<RequestInterceptor> 请求拦截器
  6. SetterFactory
  7. QueryMapEncoder 将参数转换为map的编码器
  8. Capability (MicrometerObservationCapability and CachingCapability)增强器

3. 覆盖Feign默认的Bean组件

  1. 方式一

    1. 全局覆盖
    @Configuration
    public class FooConfiguration {@Beanpublic Contract feignContract() {return new feign.Contract.Default();}@Beanpublic BasicAuthRequestInterceptor basicAuthRequestInterceptor() {return new BasicAuthRequestInterceptor("user", "password");}
    }
    
  2. 方式二

    1. 单独覆盖FeignClient
    @FeignClient(name = "stores", configuration = FooConfiguration.class)
    public interface StoreClient {
    }
    public class FooConfiguration{@Beanpublic Contract feignContract() {return new feign.Contract.Default();}
    }
    

5. Feign的yaml/properties配置(等价于@Bean配置)

1. 默认情况,配置类和yaml配置效果一样,都是给核心Feign进行配置,配置文件优先于@Bean配置,如果同时存在,配置文件中配置的覆盖@Bean配置的
1. 如果需要让@Bean的优先,则使用`spring.cloud.openfeign.client.default-to-properties=false`来禁用默认的配置优先
spring:cloud:openfeign:client:config:# feignClient名称feignName:// @FeignClient的url,优先取用@FeignClient的URL,再取用配置属性文件中设置的url,最后使用默认的url,http://服务名url: http://remote-service.com// 设置连接超时时间connectTimeout: 5000// 设置请求超时时间readTimeout: 5000// 设置日志级别loggerLevel: full// 设置异常解码器errorDecoder: com.example.SimpleErrorDecoder// 设置重试机制retryer: com.example.SimpleRetryer// 添加默认的请求参数defaultQueryParameters:query: queryValue// 添加默认的请求头defaultRequestHeaders:header: headerValue// 设置请求拦截器requestInterceptors:- com.example.FooRequestInterceptor- com.example.BarRequestInterceptor// 设置响应拦截器responseInterceptor: com.example.BazResponseInterceptor// 设置是否处理404dismiss404: false// 设置编码器encoder: com.example.SimpleEncoder// 设置解码器decoder: com.example.SimpleDecoder// Contract 接口定义了如何根据 Java 接口的注解创建请求和解析响应// Contract 接口是 Feign 的一个核心接口,它可以自定义 Feign 客户端与服务端之间的契约规则,例如支持不同的注解风格、参数传递方式等// 通过实现自定义的 Contract 接口,可以更灵活地定制 Feign 客户端与服务端之间的通信行为// 该类负责解析一些注解SpringMVC的注解信息,校验哪些注解是否标注错误,解析方法上的RequestMapping注解,参数上的Param注解等// 解析到的注解信息,然后交给RequestTemplate// 例如://  @CollectionFormat: 集合类型的数据如何传递,CSV,\t,|分割等等//  @RequestMapping解析,@Param,@SpringQueryMap,@QueryMap,@RequestParam处理// 该类还包含对应注解的参数解析器contract: com.example.SimpleContract// 设置将以上描述的组件进行增强的接口// 该接口的定义: A enrich (A a){return a;},给你指定参数,让你增强,返回增强后的组件capabilities:- com.example.FooCapability- com.example.BarCapability// 设置将请求参数对象转换为map的编码器queryMapEncoder: com.example.SimpleQueryMapEncoder# 开启链路追踪micrometer.enabled: false

6. Feign对CircuitBreaker熔断的支持

  1. 如果存在CircuitBreaker实现,可以使用配置spring.cloud.openfeign.circuitbreaker.enabled=true启用熔断

  2. 如果想禁用FeignClient的熔断支持,可以配置一个Feign.Builder的Bean,该Builder创建的代理对象不会处理熔断

    @Configuration
    public class FooConfiguration {@Bean// 注意: 该Bean要注册为原型的,对于每一个FeignClient都互不影响@Scope("prototype")public Feign.Builder feignBuilder() {return Feign.builder();}
    }// 如果开启了熔断,那么默认注册的Builder对象为FeignCircuitBreaker.builder,该对象创建的代理对象支持熔断机制,如果需要禁用,我们需要配置Feign.builder来禁用该Builder的注册
    @Bean
    @Scope("prototype")
    @ConditionalOnMissingBean
    @ConditionalOnBean(CircuitBreakerFactory.class)
    public Feign.Builder circuitBreakerFeignBuilder() {return FeignCircuitBreaker.builder();
    }
    
  3. 对于断路器的名称格式为: <feignClientClassName>#<calledMethod>(<parameterTypes>),例如``FooFeignClient#bar(),如果要修改默认的名称格式,提供一个CircuitBreakerNameResolver `Bean

    @Configuration
    public class FooConfiguration {@Beanpublic CircuitBreakerNameResolver circuitBreakerNameResolver() {return (String feignClientName, Target<?> target, Method method) -> feignClientName + "_" + method.getName();}
    }
    
  4. 配置属性文件配置熔断

    spring:cloud:openfeign:circuitbreaker:enabled: truealphanumeric-ids:enabled: true
    resilience4j:# 熔断配置circuitbreaker:instances:spring-cloud-order:minimumNumberOfCalls: 69# 时间超时限制配置timelimiter:instances:spring-cloud-order:timeoutDuration: 10s
    
    1. 如果想切换为以前2022.0.0版本的熔断名称,可以使用spring.cloud.openfeign.circuitbreaker.alphanumeric-ids.enabled: false配置
  5. Feign的熔断机制-服务降级

    @FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
    protected interface TestClient {@GetMapping("/hello")Hello getHello();@GetMapping("/hellonotfound")String getException();}
    // 服务降级处理类
    @Component
    static class Fallback implements TestClient {@Overridepublic Hello getHello() {throw new NoFallbackAvailableException("Boom!", new RuntimeException());}@Overridepublic String getException() {return "Fixed response";}}
    
    @FeignClient(name = "testClientWithFactory", url = "http://localhost:${server.port}/",fallbackFactory = TestFallbackFactory.class)
    protected interface TestClientWithFactory {@GetMapping("/hello")Hello getHello();@GetMapping("/hellonotfound")String getException();}@Component
    static class TestFallbackFactory implements FallbackFactory<FallbackWithFactory> {@Overridepublic FallbackWithFactory create(Throwable cause) {return new FallbackWithFactory();}}static class FallbackWithFactory implements TestClientWithFactory {@Overridepublic Hello getHello() {throw new NoFallbackAvailableException("Boom!", new RuntimeException());}@Overridepublic String getException() {return "Fixed response";}}
    
    1. 注意: 在当使用Feign和Spring Cloud CircuitBreaker进行服务降级时,ApplicationContext中有多个相同类型的bean,一个是FeignClient,一个为兜底的处理类。这将导致@Autowired无法工作,因为存在多个Bean。为了解决这个问题,Spring Cloud OpenFeign将所有Feign实例(FeignClient)标记为@Primary,这样Spring框架就知道要注入哪个bean

      1. 但是在某些情况下,这可能是不可取的,因为我们有自己所指定的Bean,因此要关闭此行为,请将@FeignClient的主要属性设置为false

        @FeignClient(name = "hello", primary = false)
        public interface HelloClient {
        }    
        

7. Feign对链路追踪Micrometer 的支持

  1. Feign提供了一个增强机制Capability,它可以对Fegin的核心组件进行加工,接收核心组件参数,返回类型一样的组件

  2. Micrometer链路追踪就是通过这个实现

    # 所有的FeignClient生效
    spring.cloud.openfeign.micrometer.enabled=true
    # 单个FeignClient生效
    spring.cloud.openfeign.client.config.feignName(Feign客户端名称).micrometer.enabled=true
    
    1. 通过以上配置,会自动导入两个Bean
    	@Configuration(proxyBeanMethods = false)@ConditionalOnProperty(name = "spring.cloud.openfeign.micrometer.enabled", matchIfMissing = true)@ConditionalOnClass({ MicrometerObservationCapability.class, MicrometerCapability.class, MeterRegistry.class })@Conditional(FeignClientMicrometerEnabledCondition.class)protected static class MicrometerConfiguration {@Bean@ConditionalOnMissingBean@ConditionalOnBean(type = "io.micrometer.observation.ObservationRegistry")public MicrometerObservationCapability micrometerObservationCapability(ObservationRegistry registry) {return new MicrometerObservationCapability(registry);}@Bean@ConditionalOnBean(type = "io.micrometer.core.instrument.MeterRegistry")@ConditionalOnMissingBean({ MicrometerCapability.class, MicrometerObservationCapability.class })public MicrometerCapability micrometerCapability(MeterRegistry registry) {return new MicrometerCapability(registry);}}
    
    1. 我们可以根据需要自定设置配置属性启用或者自己手动配置下面两个Bean

8. Feign的细节配置

  1. 如果存在多个相同服务名称的FeignClient,我们需要使用contextId属性进行表示,防止Bean名称冲突

    @FeignClient(contextId = "fooClient", name = "stores", configuration = FooConfiguration.class)
    public interface FooClient {
    }@FeignClient(contextId = "barClient", name = "stores", configuration = BarConfiguration.class)
    public interface BarClient {
    }
    
  2. 如果想让某一个FeignClient的独立ApplicationContext不继承父容器的Bean信息,这样也可以达到配置隔离,但是可能会有,所有的Bean都有FeignClient自身的ApplicationContext产生,我们可以使用FeignClientConfigurer配置

    @Configuration
    public class CustomConfiguration {@Beanpublic FeignClientConfigurer feignClientConfigurer() {return new FeignClientConfigurer() {@Overridepublic boolean inheritParentConfiguration() {return false;}};}
    }
    
  3. 默认情况下,Feign不会解码"/“,例如”/“编码为”%2F",“%2F"解码为”/“,可以通过spring.cloud.openfeign.client.decodeSlash: false则会进行解码,将”%2F"解码为"/"

  4. SpringEncoder编码器,将请求参数编码为请求体对象,编码为请求体默认字符集固定为UTF-8,如果需要修改这种行为,则spring.cloud.openfeign.encoder.charset-from-content-type: true

  5. 如果想使用自定义的FeignClient客户端,不使用Feign自动创建的代理对象,我们可以仿照源码操作

    @Import(FeignClientsConfiguration.class)
    class FooController {private FooFeignClient fooClient;private FooFeignClient adminClient;@Autowiredpublic FooController(Client client, Encoder encoder, Decoder decoder, Contract contract, MicrometerObservationCapability micrometerObservationCapability) {this.fooClient = Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract).addCapability(micrometerObservationCapability).requestInterceptor(new BasicAuthRequestInterceptor("user", "user")).target(FooClient.class, "https://PROD-SVC");this.adminClient = Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract).addCapability(micrometerObservationCapability).requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")).target(FooClient.class, "https://PROD-SVC");}
    }
    
  6. 在Feign中,FeignClient接口是可以作为模板进行继承和实现的,例如

    1. FeignClient接口不应该在服务器(接收请求端)和客户端(发送请求端)之间共享,并且不在支持类级别上的@RequestMapping标注
    public interface UserService {@GetMapping("/users/{id}")User getUser(@PathVariable("id") long id);
    }
    @RestController
    public class UserResource implements UserService {}
    @FeignClient("users")
    public interface UserClient extends UserService {}
    
  7. 开启请求响应GZip压缩(OkHttp默认支持GZip压缩,如果启用了OkHttp,则默认开启)

    # 开启响应的GZIP压缩功能
    spring.cloud.openfeign.compression.response.enabled=true
    # 开启请求的GZIP压缩功能
    spring.cloud.openfeign.compression.request.enabled=true
    # 触发压缩的请求数据类型
    spring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/json
    # 最小触发的压缩大小KB
    spring.cloud.openfeign.compression.request.min-request-size=2048
    
  8. Feign的日志配置

    1. yml配置

      1. 配置指定FeignClient的日志级别

        logging.level.project.user.UserFeignClient: DEBUG

    2. 使用@Bean配置

      1. 只需要提供Logger.Level这个Bean,并给定日志级别
        1. 全局的和FeignClient独立的参考覆盖默认配置
      @Configuration
      public class FooConfiguration {@BeanLogger.Level feignLoggerLevel() {return Logger.Level.FULL;}
      }
      
  9. Feign的缓存配置

  10. 如何开启了缓存 @EnableCaching,会自动增强InvocationHandlerFactory,该类是增强创建代理对象执行器InvocationHandler的厂,因此我们创建代理对象的InvocationHandler也具有了缓存的功能

    public class CachingCapability implements Capability {// Spring对缓存创建代理对象的拦截器,只需要执行该拦截器的invoke方法就会触发缓存操作private final CacheInterceptor cacheInterceptor;public CachingCapability(CacheInterceptor cacheInterceptor) {this.cacheInterceptor = cacheInterceptor;}@Overridepublic InvocationHandlerFactory enrich(InvocationHandlerFactory invocationHandlerFactory) {return new FeignCachingInvocationHandlerFactory(invocationHandlerFactory, cacheInterceptor);}}
    
    public class CachingCapability implements Capability {private final CacheInterceptor cacheInterceptor;public CachingCapability(CacheInterceptor cacheInterceptor) {this.cacheInterceptor = cacheInterceptor;}@Overridepublic InvocationHandlerFactory enrich(InvocationHandlerFactory invocationHandlerFactory) {return new FeignCachingInvocationHandlerFactory(invocationHandlerFactory, cacheInterceptor);}}
    
  11. 使用缓存

    public interface DemoClient {@GetMapping("/demo/{filterParam}")// 缓存接口的结果@Cacheable(cacheNames = "demo-cache", key = "#keyParam")String demoEndpoint(String keyParam, @PathVariable String filterParam);
    }
    
  12. 转发报文头的支持

    spring.cloud.loadbalancer.x-forwarded.enabled=true
    
  13. OAuth2的支持

    spring.cloud.openfeign.oauth2.enabled=true
    
  14. 注解支持

    1. @QueryMap

      1. 将请求参数自动转换为Map,使用Map接收参数
       @RequestLine("GET /api/data")
      void getData(@QueryMap Map<String, Object> queryParams);
      
    2. @SpringQueryMap

      1. 将请求参数自动转换为JavaBean对象
      @GetMapping(path = "/demo")
      String demoEndpoint(@SpringQueryMap Params params);
      
    3. @MatrixVariable矩阵变量

      @GetMapping("/objects/links/{matrixVars}")
      Map<String, List<String>> getObjects(@MatrixVariable Map<String, List<String>> matrixVars);
      
    4. @CollectionFormat

      1. 将集合类型的参数以指定的格式进行编码
      @FeignClient(name = "demo")
      protected interface DemoFeignClient {@CollectionFormat(feign.CollectionFormat.CSV)@GetMapping(path = "/test")ResponseEntity performRequest(List<String> test);@RequestLine("GET /api/resource?ids={ids}")void getResource(@Param(value = "ids", collectionFormat = CollectionFormat.CSV) List<String> ids);}
      
  15. FeignClinet中URL的配置

```
// 指定url发送请求,不支持负载均衡,并且url不会再刷新(即使配置属性发生改变)
@FeignClient(name="testClient", url="http://localhost:8081")
# 等价于下面,如果同时存在,则@FeignClient生效
spring.cloud.openfeign.client.config.testClient.url=http://localhost:8081// 组合配置,请求到指定的url,该url可以被刷新,当配置属性发生改变的时候,该FeignClient请求的url会进行刷新
@FeignClient(name="testClient")
spring.cloud.openfeign.client.config.testClient.url=http://localhost:8081
# 开启URL刷新机制,中将该URL当成事一个Bean,当发送请求的时候,从这个Bean中获取url
spring.cloud.openfeign.client.refresh-enabled=true// 最简配置,按照Feign客户端名称解析,所有的系统自动处理,支持负载均衡
@FeignClient(name="testClient")
```
  1. 对Feign构造好的Request对象进行加工转换的扩展类LoadBalancerFeignRequestTransformer

    1. 该对象返回的Request对象才是最终发送请求的Reqeust对象
    @Bean
    public LoadBalancerFeignRequestTransformer transformer() {return new LoadBalancerFeignRequestTransformer() {@Overridepublic Request transformRequest(Request request, ServiceInstance instance) {Map<String, Collection<String>> headers = new HashMap<>(request.headers());headers.put("X-ServiceId", Collections.singletonList(instance.getServiceId()));headers.put("X-InstanceId", Collections.singletonList(instance.getInstanceId()));return Request.create(request.httpMethod(), request.url(), headers, request.body(), request.charset(),request.requestTemplate());}};
    }
    

2. SpringCloud LoadBalance负载均衡

1. 概念

  1. Spring Cloud提供了自己的客户端负载均衡器的抽象和实现
  2. 对于负载均衡机制,增加了ReactiveLoadBalancer接口,并为其提供了基于轮询和随机的实现。
  3. 为了从响应式中选择服务实例,使用了ServiceInstanceListSupplier,支持ServiceInstanceListSupplier基于服务发现的实现,它使用类路径中可用的DiscoveryClient(注册中心)中检索可用实例
  4. 负载均衡官网

2. 功能

  1. 依赖

    <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
    
  2. 开启与禁用负载均衡(默认启用)

    spring.cloud.loadbalancer.enabled=false
    
  3. 默认情况下LoadBalancerClient是懒加载的,只有在第一次负载均衡的时候才会加载该实例

    public class BlockingLoadBalancerClient implements LoadBalancerClient {@Overridepublic <T> ServiceInstance choose(String serviceId, Request<T> request) {// 这里才会加载loadBalancerClientReactiveLoadBalancer<ServiceInstance> loadBalancer = loadBalancerClientFactory.getInstance(serviceId);if (loadBalancer == null) {return null;}Response<ServiceInstance> loadBalancerResponse = Mono.from(loadBalancer.choose(request)).block();if (loadBalancerResponse == null) {return null;}return loadBalancerResponse.getServer();}
    }
    
    1. 如果想要LoadBalancerClient立即加载,则可以使用spring.cloud.loadbalancer.eager-load.clients配置

      spring.cloud-loadbalancer.eager-load.clients[0]=my-first-client
      spring.cloud-loadbalancer.eager-load.clients[1]=my-second-client// 实现原理
      @Bean
      public LoadBalancerEagerContextInitializer loadBalancerEagerContextInitializer(
      LoadBalancerClientFactory clientFactory, 
      // 该配置就是spring.cloud-loadbalancer.eager-load,而下面就是获取该配置的客户端进行加载
      LoadBalancerEagerLoadProperties properties) {return new LoadBalancerEagerContextInitializer(clientFactory, properties.getClients());
      }
      // 监听容器准备完成事件
      public LoadBalancerEagerContextInitializer implements ApplicationListener<ApplicationReadyEvent> {@Overridepublic void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {serviceNames.forEach(factory::getInstance);}
      }
      
  4. 切换默认的负载均衡算法

    1. 默认的负载均衡算法为轮训

      @Configuration(proxyBeanMethods = false)
      @ConditionalOnDiscoveryEnabled
      public class LoadBalancerClientConfiguration {@Bean@ConditionalOnMissingBeanpublic ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
      }
      
    2. 如果需要切换负载均衡算法,则可以提供该Bean

      1. 设置为随机算法

        public class CustomLoadBalancerConfiguration {@BeanReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);}
        }
        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/18153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Day25

Day25 网络编程概念 计算机网络 网络编程&#xff1a;TCP协议的三次握手四次挥手 IP地址&#xff0c;端口号&#xff1a;取值范围&#xff1a;065535&#xff0c;保留端口号&#xff1a;01024。 网络协议&#xff1a;TCP协议&#xff08;类比于打电话&#xff0c;双方需要连接…

项目构建工具maven

一、概述 1、maven是apache的一个开源项目&#xff0c;是一个优秀的项目构建/管理工具 2、apache(软件基金会、非盈利组织、管理维护一些开源项目) 二、功能 1、管理项目中jar包和jar包与jar包之间的依赖 2、完成项目编译、测试、打包 三、核心文件 pom.xml:在里面配置相…

信息学奥赛初赛天天练-14-阅读程序-字符数组、唯一分解定理应用

更多资源请关注纽扣编程微信公众号 1 2019 CSP-J 阅读程序1 (程序输入不超过数组或字符串定义的范围&#xff1b;判断题正确填√,错误填&#xff1b;除特殊说明外&#xff0c;判断题1.5分&#xff0c;选择题3分&#xff0c;共计40分) 1 输入的字符串只能由小写字母或大写字母组…

Redis的非关系型数据库

第七天课堂笔记 今日目标 非关系型数据库&#xff08;nosql【not only SQL】数据库&#xff09; Redis的非关系型数据库 Redis的安装和配置 Redis常见数据类型 Redis特性 nosql数据库 not only sql数据库&#xff0c;非关系型数据库&#xff0c;往往采用类似于json来存储数…

【大宗】第一期:大航海时代下的[集运欧线]

一、大航海时代 - 集运欧线前世今生 01 航运合约指数的诞生 ‍‍‍‍ 2023年8月18日&#xff0c;上海期货交易所的伙伴们搞了个大新闻——他们推出了一种新的期货品种&#xff0c;叫做“欧线集运”。这可不是什么普通的期货&#xff0c;它是基于一个叫做SCFIS的指数&#xf…

上海汇正财经官网怎么样?客户好评如潮,口碑赞誉之声不绝于耳

在财经服务领域&#xff0c;客户评价是衡量一家企业信誉和服务质量的重要标准。上海汇正财经作为业内知名的财经服务平台&#xff0c;以其优质的服务赢得了广大客户的认可和好评。大量正面用户评价和成功服务的案例&#xff0c;充分证明了上海汇正财经是一个值得信赖的正规企业…

每日两题 / 131. 分割回文串 42. 接雨水(LeetCode热题100)

131. 分割回文串 - 力扣&#xff08;LeetCode&#xff09; 数据量较小&#xff0c;考虑直接暴力&#xff0c;每次dfs&#xff1a;以bg作为左区间&#xff0c;往右遍历&#xff0c;找到一段回文串区间后&#xff0c;将回文串插入vector<string>&#xff0c;并以下一个下标…

段位在于面对人性之恶,一笑而过

这个小哥哥不知道是哪里不对劲了&#xff0c;突然给我留言说我在骗流量&#xff0c;骗关注。公众号是我的&#xff0c;文章是我写的&#xff0c;主要分享的就是我创业的一些接单案例&#xff0c;因为之前收到很多无效的留言&#xff0c;寻求合作就几个字我不想接收无效信息&…

Day18学习Java

File - 文件类 File&#xff0c;是文件和目录路径名的抽象表示。 File只关注文件本身的信息&#xff0c;而不能操作文件里面的内容。 File类 – 表示文件或文件夹&#xff0c;不能对文件里的数据进行操作。 对文件里的数据进行操作的是&#xff1a;IO流。 需求1&#xff1a;通…

Unity 权限 之 Android 【权限 动态申请】功能的简单封装

Unity 权限 之 Android 【权限 动态申请】功能的简单封装 目录 Unity 权限 之 Android 【权限 动态申请】功能的简单封装 一、简单介绍 二、Android 权限 动态申请 三、实现原理 四、注意事项 五、案例实现简单步骤 附录&#xff1a; 一、进一步优化 二、多个权限申请…

第三方软件检测机构要具备哪些资质要求?专业测试报告如何申请?

第三方软件检测机构是独立于软件开发商和用户之外的公正机构&#xff0c;负责对软件进行全面的检测和评估。其独立性保证了评测结果的客观性和公正性&#xff0c;有效避免了软件开发商对自身产品的主观偏见和误导。 要成为一家合格的第三方软件检测机构&#xff0c;需要具备一…

网络编程——多进程的服务器

多进程的网络服务器 多进程的网络服务器是一种使用多个进程来处理并发网络请求的服务器架构。在这种架构中&#xff0c;服务器在接收到客户端连接请求后&#xff0c;会创建一个新的子进程来处理该请求&#xff0c;从而允许服务器同时处理多个客户端连接。多进程服务器通常用于…

OKR 实践:来自一位信息技术部主管的成功秘诀

OKR 实践&#xff1a;来自一位信息技术部主管的成功秘诀 为什么选择OKR 公司信息技术部为38个各地分公司、12,000名员工的IT需求提供服务。庞大而多样的客户群常常使我们的团队分散&#xff0c;许多团队都在各自为政&#xff0c;以个案为基础解决问题&#xff0c;而不是采用企业…

线上监控诊断利器:Arthas,你值得拥有

1. 引言 在现代软件开发中&#xff0c;线上监控和诊断是确保应用稳定性和性能的关键环节。然而&#xff0c;对于Java开发者来说&#xff0c;传统的监控工具往往难以深入到代码层面进行实时分析。这正是Arthas这一线上监控诊断工具大展身手的地方。本文将深入探讨Arthas&#x…

LabVIEW高低温试验箱控制系统

要实现LabVIEW高低温试验箱控制系统&#xff0c;需要进行硬件配置、软件设计和系统集成&#xff0c;确保LabVIEW能够有效地监控和控制试验箱的温度。以下是详细说明&#xff1a; 硬件配置 选择合适的试验箱&#xff1a; 确定高低温试验箱的型号和品牌。 确认试验箱是否支持外…

摸鱼大数据——Hive表操作——文件数据的导入和导出

数据导入和导出 1、文件数据导入 1.1 直接上传文件 window页面上传 需求: 已知emp1.txt文件在windows/mac系统,要求使用hdfs保存此文件 并且使用hivesql建表关联数据 use day06; ​ -- 1- 创建Hive表 create table emp1 (id int,name string,salary int,dept string )row for…

基于51单片机的汽车智能灯光控制系统

一.硬件方案 本设计硬件部分&#xff0c;中央处理器采用了STC89C52RC单片机&#xff0c;另外使用两个灯珠代表远近光灯&#xff0c;感光部分采用了光敏电阻&#xff0c;因为光敏电阻输出的是电压模拟信号&#xff0c;单片机不能直接处理模拟信号&#xff0c;所以经过ADC0832进…

基于python flask +pyecharts实现的气象数据可视化分析大屏

背景 气象数据可视化分析大屏基于Python Flask和Pyecharts技术&#xff0c;旨在通过图表展示气象数据的分析结果&#xff0c;提供直观的数据展示和分析功能。在当今信息化时代&#xff0c;气象数据的准确性和实时性对各行业具有重要意义。通过搭建气象数据可视化分析大屏&…

Vue 3 教程:入门指南

Vue 3 教程&#xff1a;入门指南 Vue 3 教程&#xff1a;入门指南 Vue 3 教程&#xff1a;入门指南引言1. 初始化项目2. 响应式数据使用 ref使用 reactive 3. 计算属性4. 侦听器5. 组合式 API6. 总结 引言 Vue.js 是一个用于构建用户界面的渐进式框架。Vue 3 引入了许多新的特…

Qt子线程更新UI的一种新玩法

目录 1. 说明2. 场景3. 子线程更新UI的方法3.1 一般做法3.2 新玩法 1. 说明 Qt不允许子线程直接操作主线程UI&#xff0c;推荐的做法是&#xff0c;子线程发送信号&#xff0c;主线程响应该信号。其最终的效果&#xff0c;依旧不是子线程直接操作主线程UI。 2. 场景 假设现在…