基於java智能物流管理系統設計與實現,可適用於校園物流管理系統,物流配送系統,快遞物流管理,物流追蹤系統,物流系統,物流運輸系統,javaweb物流系統,springboot物流管理系統,javaweb智能物流系統等等; ...
項目研發過程中,經常會遇到與測試人員工作重疊的情況,十分影響效率。
做了一個修改,可以在本地環境啟動項目後和測試環境交互,並且不影響測試環境,理論上也可以用於線上環境的異常的快速處理。
準備事項如下:
一:搭建本地的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