• SpringCloud : Feign 不捆绑远程应用名称, 实现服务应用名称传入,调用通用自动化


    Feign 版本10.1.0

    Spring 版本 5.1.5.RELEASE

    SpringBoot 版本 2.1.5.RELEASE

    SpringCloud 版本 2.1.1.RELEASE

    大家知道,使用Feigen调用远端微服务的代码大致如下:

    定义接口参数:

    @FeignClient(name = "remote-service-name")
    public interface XxxServiceClient{
    
        @PostMapping(value = "/xxx/xxx", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        JSONObject callXxx(@RequestBody Xxx param);
    }

    然后如下调用:

    @Slf4j
    @Service
    public class MyLogic {
    
        @Autowired
        private XxxServiceClient xxxServiceClient;
        
        public void sendMqMessage() {
            Xxx param = new Xxx();
            JSONObject rsp = xxxServiceClient.callXxx(param);
        }
    }

    但一般的常规应用、业务如此调用没什么问题。但如果该应用是一个转发代理、或者路由网关服务。那么如此调用就很不合理,而且硬编码的化代码臃肿且不可配置化。

    网上找了很多资料,发现如下用法可行。

    方案:

    先编写一个组件类:

    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import com.alibaba.fastjson.support.config.FastJsonConfig;
    import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
    import com.alibaba.fastjson.support.springfox.SwaggerJsonSerializer;
    import com.netflix.appinfo.InstanceInfo;
    import com.netflix.discovery.EurekaClient;
    import com.yunplus.bpg.wechat.proxy.dto.mp.msg.notify.NotifyEventDto;
    import com.yunplus.bpg.wechat.proxy.dto.mp.msg.reply.ReplyDiyMsgDto;
    import com.yunplus.commons.misc.dto.ApiResultDto;
    import feign.Client;
    import feign.Contract;
    import feign.Feign;
    import feign.Request;
    import feign.codec.Decoder;
    import feign.codec.Encoder;
    import org.springframework.beans.factory.ObjectFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
    import org.springframework.cloud.openfeign.FeignContext;
    import org.springframework.cloud.openfeign.support.SpringDecoder;
    import org.springframework.cloud.openfeign.support.SpringEncoder;import org.springframework.http.MediaType;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.net.URI;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    import java.util.concurrent.ConcurrentHashMap;
    
    
    /**
     * 自定义feigen客户端配置
     *
     * @author phpdragon
     */
    @Component
    public class RemoteService {
    
        /**
         * FeignClientFactoryBean 该工厂类中 设置builder属性时就是通过该对象,源码中可看到
         */
        @Autowired
        protected FeignContext feignContext;
    
        /**
         * FeignClient 默认LoadBalancerFeignClient
         */
        @Autowired
        private Client feignClient;
    
        /**
         * 通过注入Eureka实例对象,就不用手动指定url,只需要指定服务名即可
         */
        @Autowired
        protected EurekaClient eurekaClient;
    
        private static final Map<String, Object> FEIGN_CLIENTS = new ConcurrentHashMap<>();
    
        /**
         * 定义远程通用接口
         */
        public interface RemoteFeignClient {
            @ResponseBody
            @PostMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
            JSONObject doSomething(URI uri, Xxx  param);
        }
    
        /**
         * @param serverId
         * @return
         */
    public RemoteFeignClient getClient(String serverId) { return this.create(RemoteFeignClient.class, serverId); } /** * 设置编码解码器为FastJson * * @param clazz * @param serverId * @param <T> * @return */ private <T> T create(Class<T> clazz, String serverId) { InstanceInfo nextServerFromEureka = eurekaClient.getNextServerFromEureka(serverId, false); Object object = FEIGN_CLIENTS.get(nextServerFromEureka.getIPAddr()); if (Objects.isNull(object)) { object = Feign.builder() //encoder指定对象编码方式 .encoder(this.feignEncoder()) //decoder指定对象解码方式 .decoder(this.feignDecoder()) .client(feignClient) //options方法指定连接超时时长及响应超时时长 .options(new Request.Options(5000, 5000)) //retryer方法指定重试策略 //.retryer(new Retryer.Default(5000, 5000, 3)) .contract(feignContext.getInstance(serverId, Contract.class)) //target方法绑定接口与服务端地址。返回类型为绑定的接口类型。 .target(clazz, nextServerFromEureka.getHomePageUrl()); FEIGN_CLIENTS.put(nextServerFromEureka.getIPAddr(), object); } return (T) object; } private Encoder feignEncoder() { return new SpringEncoder(feignHttpMessageConverter()); } private Decoder feignDecoder() { return new SpringDecoder(feignHttpMessageConverter()); } /** * 设置解码器为fastjson * * @return */ private ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() { final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(this.getFastJsonConverter()); return () -> httpMessageConverters; } private FastJsonHttpMessageConverter getFastJsonConverter() { FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); List<MediaType> supportedMediaTypes = new ArrayList<>(); MediaType mediaTypeJson = MediaType.valueOf(MediaType.APPLICATION_JSON_UTF8_VALUE); supportedMediaTypes.add(mediaTypeJson); converter.setSupportedMediaTypes(supportedMediaTypes); FastJsonConfig config = new FastJsonConfig(); config.getSerializeConfig().put(JSON.class, new SwaggerJsonSerializer()); config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect); converter.setFastJsonConfig(config); return converter; } }

    然后如下调用:

    @Slf4j
    @Service
    public class MyLogic {
    
        @Autowired
        private RemoteClientService  remoteClientService;
        
        public void callDownstreamService() {
            //这里的url直接使用SpringCloud应用名作为host
            String = "http://server-name/xxx/xxxx";
            URI uri = UrlUtil.newUri(url);
            Xxx param = new Xxx();
            JSONObject rsp = remoteService.getClient(uri.getHost()).doSomething(uri, param);
        }
    }

    如此,便实现了自动转发、调用代理等路由功能。然后再接口数据库,一个自动转发的服务遍完成。

    PS:

    https://www.jianshu.com/p/2a3965049f77

    https://www.jianshu.com/p/3d597e9d2d67/

  • 相关阅读:
    中国象棋评估函数建模
    C语言中指针变量传参
    STM32外部中断
    C语言中的注释
    STM32学习网址
    C语言中的布尔值
    更改KEIL背景配色
    Modbus通讯协议
    DUP
    算法的时间复杂度
  • 原文地址:https://www.cnblogs.com/phpdragon/p/12119065.html
Copyright © 2020-2023  润新知