• 研发提速:nacos+openfeign环境下的本地链接服务


    项目研发过程中,经常会遇到与测试人员工作重叠的情况,十分影响效率。

    做了一个修改,可以在本地环境启动项目后和测试环境交互,并且不影响测试环境,理论上也可以用于线上环境的异常的快速处理。

    准备事项如下:

    一:搭建本地的nacos服务。

    二:导入测试环境相应项目的nacos配置文件。

    三:新增代码:

    修改LoadBalancerFactory获取服务host的方式,由于是本地启动的项目,并且连接的还是本地的nacos,所以项目启动后,肯定不会注册到测试环境,相对的也获取不到测试环境的其他服务。

    由于本人使用的时候是基于CachingSpringLoadBalancerFactory ,如果直接使用时不生效或者异常,可以DEBUG跟踪一下自己框架调用服务时使用的具体LoadBalancerFactory类。

    复制代码
      3 import cn.hutool.http.HttpUtil;
      4 import com.alibaba.fastjson.JSON;
      5 import com.alibaba.fastjson.JSONArray;
      6 import com.alibaba.fastjson.JSONObject;
      7 import com.netflix.client.config.IClientConfig;
      8 import com.netflix.loadbalancer.ILoadBalancer;
      9 import com.netflix.loadbalancer.Server;
     10 import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
     11 import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
     12 import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
     13 import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
     14 import org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer;
     15 import org.springframework.cloud.openfeign.ribbon.RetryableFeignLoadBalancer;
     16 import org.springframework.util.ConcurrentReferenceHashMap;
     17 import org.springframework.util.ObjectUtils;
     18 
     19 import java.util.ArrayList;
     20 import java.util.List;
     21 import java.util.Map;
     22 
     23 public class DevCachingSpringLoadBalancerFactory extends CachingSpringLoadBalancerFactory {
     24 
     25     private volatile Map cache = new ConcurrentReferenceHashMap<>();
     26     private volatile Map> server = new ConcurrentReferenceHashMap<>();
     27     private volatile String ip;
     28     private volatile String port;
     29     private volatile String namespaceid;
     30 
     31     public DevCachingSpringLoadBalancerFactory(SpringClientFactory factory) {
     32         super(factory);
     33     }
     34 
     35     public DevCachingSpringLoadBalancerFactory(SpringClientFactory factory, LoadBalancedRetryFactory loadBalancedRetryPolicyFactory) {
     36         super(factory, loadBalancedRetryPolicyFactory);
     37     }
     38 
     39     public boolean initialize(String ip,String port,String namespaceid) {
     40         this.ip = ip;
     41         this.port = port;
     42         this.namespaceid = namespaceid;
     43         return null != ip ? null != port ?  null != namespaceid ? true : false :false :false;
     44     }
     45 
     46     @Override
     47     public FeignLoadBalancer create(String clientName) {
     48         FeignLoadBalancer client = this.cache.get(clientName);
     49         if (client != null) {
     50             return client;
     51         }
     52         IClientConfig config = this.factory.getClientConfig(clientName);
     53         ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
     54 
     55         //修改部分
     56         List list = lb.getAllServers();
     57         if (null == list || ObjectUtils.isEmpty(list)) list = new ArrayList<>();
     58         list.addAll(Servers(clientName));
     59         lb.addServers(list);
     60 
     61         ServerIntrospector serverIntrospector = this.factory.getInstance(clientName,
     62                 ServerIntrospector.class);
     63         client = this.loadBalancedRetryFactory != null
     64                 ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
     65                 this.loadBalancedRetryFactory)
     66                 : new FeignLoadBalancer(lb, config, serverIntrospector);
     67         this.cache.put(clientName, client);
     68         return client;
     69     }
     70 
     71     /**
     72      * 获取server
     73      * 返回数组,重试机制交由原框架
     74      * http://ip:port/nacos/v1/ns/instance/list?namespaceId=namespaceid&serviceName=client
     75      */
     76     public List Servers(String client) {
     77         if(server.containsKey(client)) return server.get(client);
     78         else synchronized (server) {
     79             if(server.containsKey(client)) return server.get(client);
     80             else {
     81                 server.put(client,new ArrayList());
     82                 String url = new StringBuilder("http://")
     83                         .append(ip)
     84                         .append(":")
     85                         .append(port)
     86                         .append("/nacos/v1/ns/instance/list?")
     87                         .append("namespaceId=")
     88                         .append(namespaceid)
     89                         .append("&serviceName=")
     90                         .append(client).toString();
     91                 JSONObject jsonObject = JSON.parseObject(HttpUtil.get(url));
     92                 JSONArray hosts = jsonObject.getJSONArray("hosts");
     93                 for (int i = 0; i < hosts.size(); i++) {
     94                     server.get(client).add(new Server(hosts.getJSONObject(i).getString("ip"),hosts.getJSONObject(i).getInteger("port")));
     95                 }
     96                 return server.get(client);
     97             }
     98         }
     99     }
    100 
    101 }
    复制代码

    这个文件可以不用添加,主要是用来做一些其他的扩展。

    复制代码
     3 import feign.Client;
     4 import feign.Request;
     5 import feign.Response;
     6 import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
     7 import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
     8 import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
     9 
    10 import java.io.IOException;
    11 
    12 public class DevFeignClient extends LoadBalancerFeignClient{
    13 
    14     public DevFeignClient(Client delegate, CachingSpringLoadBalancerFactory lbClientFactory, SpringClientFactory clientFactory) {
    15         super(delegate, lbClientFactory, clientFactory);
    16     }
    17 
    18     @Override
    19     public Response execute(Request request, Request.Options options) throws IOException {
    20         return super.execute(request, options);
    21     }
    22 }
    复制代码

    配置文件用来替换原来IOC中的BEAN,另外用于获取后面yml文件中的自定义配置。

    复制代码
     3 import feign.Client;
     4 import org.springframework.beans.factory.annotation.Value;
     5 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
     6 import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
     7 import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
     8 import org.springframework.context.annotation.Bean;
     9 import org.springframework.context.annotation.Configuration;
    10 
    11 @Configuration
    12 public class DevFeignConfig {
    13 
    14     @ConditionalOnProperty("feign.dev.enabled")
    15     @Configuration(proxyBeanMethods = false)
    16     class DefaultFeignLoadBalancedConfiguration {
    17         @Value("${feign.dev.ip}")
    18         String ip;
    19         @Value("${feign.dev.port}")
    20         String port;
    21         @Value("${feign.dev.namespaceid}")
    22         String namespaceid;
    23 
    24 
    25         @Bean
    26         public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, DevCachingSpringLoadBalancerFactory devFactory,
    27                                   SpringClientFactory clientFactory) {
    28             System.out.println("#####################################进入本地调试模式#####################################");
    29             return new DevFeignClient(new Client.Default(null, null),null == devFactory?cachingFactory:devFactory,
    30                     clientFactory);
    31         }
    32 
    33         @Bean
    34         public DevCachingSpringLoadBalancerFactory devFactory(SpringClientFactory factory) {
    35             DevCachingSpringLoadBalancerFactory devFactory = new DevCachingSpringLoadBalancerFactory(factory);
    36             if(devFactory.initialize(ip,port,namespaceid)) return devFactory;
    37             System.out.println("#####################################本地调试模式异常#####################################");
    38             System.out.println("feign.dev.ip " + ip);
    39             System.out.println("feign.dev.port " + port);
    40             System.out.println("feign.dev.namespaceid " + namespaceid);
    41             System.out.println("#####################################本地调试模式异常#####################################");
    42             return null;
    43         }
    44     }
    45 
    46 
    47 }
    复制代码

    修改yml文件,主要是用来配置新增的自定义属性和小插件的开启和关闭。

    建议手动在本地项目的yml文件添加属性,yml文件的配置,直接复制容易出现问题。

    新增属性如下:

    feign.dev.enabled
    feign.dev.ip
    feign.dev.port
    feign.dev.namespaceid
    复制代码
    server:
      port: 服务端口号
    spring:
      application:
        name: 服务名称
      profiles:
        active: dev
      cloud:
        nacos:
          config:
            file-extension: yml
            namespace: 本地Nacos的命名空间
          username: 本地Nacos的账号
          password: 本地Nacos的密码
          server-addr: 本地Nacos的IP:本地Nacos的端口号
          discovery:
            namespace: 本地Nacos的命名空间
            group: DEFAULT_GROUP
            enabled: true
            register-enabled: true
    feign:
      dev:
        #true为开启本地调式,false为关闭
        enabled: false
        ip: 测试环境Nacos的IP
        port: 测试环境Nacos的端口号
        namespaceid:  测试环境Nacos的命名空间
      client:
        config:
          default:
            #不设置connectTimeout会导致readTimeout设置不生效
            connectTimeout: 5000
            readTimeout: 5000
    复制代码

     

  • 相关阅读:
    一米facebook功能点
    【无标题】
    HTML语义标签
    element ui框架(嵌套路由)
    优先级队列
    【数据结构】CH1 绪论3——算法分析
    01-MySQL简介和安装
    计算机毕业设计ssm儿童福利院管理系统5d7wb系统+程序+源码+lw+远程部署
    初学者设计PCB,如何检查光绘文件的断头线
    1402. 做菜顺序 --力扣 --JAVA
  • 原文地址:https://www.cnblogs.com/tangzeqi/p/17748498.html