3

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

 8 months ago
source link: https://www.cnblogs.com/tangzeqi/p/17748498.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

研发提速: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<String, FeignLoadBalancer> cache = new ConcurrentReferenceHashMap<>();
 26     private volatile Map<String, List<Server>> 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<Server> 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<Server> 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<Server>());
 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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK