Feign动态切换服务

作者: 清蒸三文鱼_ | 来源:发表于2021-08-02 14:51 被阅读0次

    概述

    通过配置进行服务切换, 如果入参和出参一致, 那么代码几乎不用改动; 示例使用用户服务为例, 通过代理类进行切换qq或微信的用户服务

    CODE

    代理类UserServiceProxy( 入参出参通用 )

    public interface UserServiceProxy {
        List<User> listUser(String name);
    }
    

    代理继承类

    这里的入参出参尽量保持一致, 当然不一样也可以通过implements来特定实现; 下面的示例为了有所区分, url的地址不同

     public   interface QQ extends UserServiceProxy{
            @GetMapping("/openapi/v2/user/list")
            List<User> listUser(@RequestParam String name);
     }
    
     public interface Wechat extends UserServiceProxy{
            @GetMapping("/openapi/v1/user/listActive")
            List<User> listUser(@RequestParam String name);
        }
    

    代理配置类ProxyConfiguration

    因为@Condition类的注解和@FeinClient无法结合使用(会导致注入失败) , 所以需要自行管理FeignClient的bean

    • 高版本的Feign(3.x+)可以使用FeignClientBuilder的customize方法, 可以指定加载feign的配置信息; 不需要自己做服务的负载均衡, taget中已经做了对应的实现
    • 低版本的需要使用其他的方式实现, 低版本的没有customize, 同时FeignClientFactoryBean是包内可见的

    高版本(3.x+)

    @Component
    public class ProxyConfiguration {
        @Value("${user.service.qq.enable:false}")
        boolean enableQqService;
        @Autowired
        ObjectFactory<HttpMessageConverters> messageConverters;
    
        @Bean
        public UserServiceProxy userProxy1(ApplicationContext context) {
            UserServiceProxy.QQ qq = new FeignClientBuilder(context)
                    .forType(UserServiceProxy.QQ.class, "qqUser")
                    .customize((ct) -> ct.contract(new SpringMvcContract())
                            .encoder(new SpringEncoder(messageConverters)).build()).build();
    
            UserServiceProxy.Wechat wechat = new FeignClientBuilder(context)
                    .forType(UserServiceProxy.Wechat.class, "wechatUser")
                    .customize((ct) -> ct.contract(new SpringMvcContract()).build()).build();
            return enableQqService ? qq : wechat;
        }
    }
    

    低版本(2.x+), 自定义Target

    @Component
    public class ProxyConfiguration {
        @Value("${user.service.qq.enable:false}")
        boolean enableQqService;
        @Autowired
        ObjectFactory<HttpMessageConverters> messageConverters;
        @Bean
        public UserServiceProxy userProxy2(@Autowired(required = false) ServiceInstanceChooser chooser) {
            CustomTarget<UserServiceProxy.QQ> qq = new CustomTarget<>(UserServiceProxy.QQ.class, "qq", "/qq_open/user", chooser);
            CustomTarget<UserServiceProxy.Wechat> wechat = new CustomTarget<>(UserServiceProxy.Wechat.class, "wechat", "/wechat_open/user", chooser);
            return enableQqService ?
                    new Feign.Builder().contract(new SpringMvcContract()).encoder(new SpringEncoder(messageConverters)).target(qq) :
                    new Feign.Builder().contract(new SpringMvcContract()).encoder(new SpringEncoder(messageConverters)).target(wechat);
        }
    
        static class CustomTarget<T> extends Target.HardCodedTarget<T> {
            private final ServiceInstanceChooser chooser;
    
            public CustomTarget(Class<T> type, String name, String url, ServiceInstanceChooser chooser) {
                super(type, name, url);
                this.chooser = chooser;
            }
    
            @Override
            public String url() {
                //使用chooser做负载均衡
                return chooser.choose(super.url()).getUri() + super.url();
            }
        }
    }
    

    POM

      <parent> 
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-parent</artifactId>  
        <version>2.5.3</version>  
        <relativePath/>  
      </parent>  
    
      <properties> 
        <java.version>1.8</java.version>  
        <spring-cloud.version>2020.0.3</spring-cloud.version> 
      </properties>  
    
      <dependencies> 
        <dependency> 
          <groupId>org.springframework.boot</groupId>  
          <artifactId>spring-boot-starter-web</artifactId> 
        </dependency>  
        <dependency> 
          <groupId>org.springframework.cloud</groupId>  
          <artifactId>spring-cloud-starter-openfeign</artifactId> 
        </dependency> 
      </dependencies> 
    
      <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
      </dependencyManagement>
    

    运行

    通过@Autowire UserServiceProxy进行方法调用, 能正确返回数据即切换成功

    相关文章

      网友评论

        本文标题:Feign动态切换服务

        本文链接:https://www.haomeiwen.com/subject/vgxjvltx.html