Feign动态切换服务

概述

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

CODE

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

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

代理继承类

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

 public   interface QQ extends UserServiceProxy{
        @GetMapping("/openapi/v2/user/list")
        List listUser(@RequestParam String name);
 }
 public interface Wechat extends UserServiceProxy{
        @GetMapping("/openapi/v1/user/listActive")
        List 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 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 messageConverters;
    @Bean
    public UserServiceProxy userProxy2(@Autowired(required = false) ServiceInstanceChooser chooser) {
        CustomTarget qq = new CustomTarget<>(UserServiceProxy.QQ.class, "qq", "/qq_open/user", chooser);
        CustomTarget 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 extends Target.HardCodedTarget {
        private final ServiceInstanceChooser chooser;

        public CustomTarget(Class 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

   
    org.springframework.boot  
    spring-boot-starter-parent  
    2.5.3  
      
    

   
    1.8  
    2020.0.3 
    

   
     
      org.springframework.boot  
      spring-boot-starter-web 
      
     
      org.springframework.cloud  
      spring-cloud-starter-openfeign 
     
   

  
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud.version}
                pom
                import
            
        
  

运行

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

你可能感兴趣的:(Feign动态切换服务)