企业管理系统定制开发gateway网关转发请求到nacos不同namespace和不同group下服务实例源码改造

问题

gateway企业管理系统定制开发转发请求到微服务,企业管理系统定制开发报错误页面,企业管理系统定制开发错误信息如下所示:

There was an unexpected error (type=Service Unavailable, status=503).
Unable to find instance xxx

企业管理系统定制开发报错信息显示找不到应用实例。即gateway企业管理系统定制开发无法在实例中获取到路企业管理系统定制开发由配置的对应实例。企业管理系统定制开发查阅网上资料,大多数写的是由于版本原因,需要手动配置ribbon中loadbalancer的jar包就可以解决问题。但是项目中SpringBoot版本为2.2.X版本,所以SpringCloud Alibaba使用的是2.2.0.RELEASE版本,此版本并不用手动配置ribbon的jar包。

补充:
SpringCloud Alibaba使用版本为2.2.0.RELEASE意思是,我们在定义nacos客户端启动类jar包,gateway启动类jar包时,对应的jar包版本都是2.2.0.RELEASE版本,只需要在父工程pom里定义SpringCloud Alibaba版本即可。其他SpringCloud Alibaba组件在配置启动类jar包时,就无需再定义版本了。

问题定位

查阅了许多资料,其中有一篇博客写道当负载转发的服务实例在nacos中与gateway服务实例在nacos里不是同一个namespace或者不是同一个group,也会报上述错误。项目中要转发的服务实例和gateway服务实例在nacos中属于同一个namespace,但是属于不同group。
于是将gateway与要转发的服务实例改成同一个group,果然可以正确转发了,不再报错了。所以,要想使用gateway进行请求转发,所有的微服务实例与gateway服务实例在nacos中必须是同一个namesapce和同一个group。

但是在本项目中,不同的微服务实例放在不同group中,是提前设计好的,有业务需要的。如果都归属于同一个group,那么会影响到其他业务实现。那么如何让gateway可以转发nacos中不同group甚至不同namespace中的服务实例呢?

解决思路

首先,需要想清楚的是,gateway只能转发在nacos中同namespace和同group中的服务实例,是谁规定的呢?我们知道,在gateway中,通过Ribbon进行负载均衡。那么,进行负载均衡的实例,是在哪里获取到的呢?在gateway中需要依赖nacos注册中心的jar包,如下:

        <dependency>			<groupId>com.alibaba.cloud</groupId>			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>		</dependency>
  • 1
  • 2
  • 3
  • 4

依赖这个jar包后,将gateway注册到nacos中,同时,这个jar包也定义了nacos中Open Api中方法的调用,可以通过调用Open Api获取到nacos中服务实例等信息。核心类是NacosServerList类。里面的核心方法是getServers()方法,源码如下所示:

private List<NacosServer> getServers() {		try {		     //获取到gateway服务实例所属分组			String group = discoveryProperties.getGroup();			//查询分组下serviceId实例,这里的serviceId就是gateway要负载均衡的服务实例。			List<Instance> instances = discoveryProperties.namingServiceInstance()					.selectInstances(serviceId, group, true);			return instancesToServerList(instances);		}		catch (Exception e) {			throw new IllegalStateException(					"Can not get service instances from nacos, serviceId=" + serviceId,					e);		}	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

由上述源码可知,nacos中默认是获取同namespace和同group下的服务实例。因为nacos中namespace和group就是用于服务隔离的,在不同的group和不同namespacae中,可以定义相同服务实例名称。所以nacos这么做无可厚非。只不过在特殊业务场景中,需要获取到不同group甚至不同namespace中服务实例。所以要对上述源码进行修改。

下面还需要分析一个问题,即我们自定义实现了NacosServerList,如何加入到源码执行的流程中呢?即在nacos执行流程中,要使用我们定义的NacosServerList类,而不是jar包中原有的NacosServerList类,应该从哪儿切入呢?在idea中,点击NacosServerList类,就会查找哪里调用这个类了,好在就一个地方初始化了这个类,那么这个类就是NacosServerList的切入,我们在这里定义我们自己的NacosServerList就行。切入类如下:

@Configuration(proxyBeanMethods = false)@ConditionalOnRibbonNacospublic class NacosRibbonClientConfiguration {	@Autowired	private PropertiesFactory propertiesFactory;	@Bean	@ConditionalOnMissingBean	public ServerList<?> ribbonServerList(IClientConfig config,			NacosDiscoveryProperties nacosDiscoveryProperties) {		if (this.propertiesFactory.isSet(ServerList.class, config.getClientName())) {			ServerList serverList = this.propertiesFactory.get(ServerList.class, config,					config.getClientName());			return serverList;		}		NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);		serverList.initWithNiwsConfig(config);		return serverList;	}	@Bean	@ConditionalOnMissingBean	public NacosServerIntrospector nacosServerIntrospector() {		return new NacosServerIntrospector();	}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

上述源码中,ribbonServerList()方法new出了NacosServerList对象,那么我们可以自己定义一个@Configuration类,覆盖这个类,来new出我们自己改造后的NacosServerList对象。这个想法是最好的解决思路,但是,经过研究发现,在NacosServerList类中,需要有IClientConfig类参与,才可以正常使用,而IClientConfig类,是框架自带的,研究了半天,完全没有搞懂这个类是干啥的。水平有限,只能放弃这种思路了。只能退而求其次,定义源码相同的包路径和类名和类名,来覆盖源码中类了。

解决方法

首先,定义NacosServerList类子类,来重写getServer()方法,获取不同分组下服务实例,代码如下:

public class AppNacosServerList extends NacosServerList {    private NacosDiscoveryProperties discoveryProperties;    private String serviceId;    public AppNacosServerList(NacosDiscoveryProperties discoveryProperties) {        super(discoveryProperties);        this.discoveryProperties=discoveryProperties;    }    @Override    public List<NacosServer> getInitialListOfServers() {        return getServers();    }    @Override    public List<NacosServer> getUpdatedListOfServers() {        return getServers();    }    /**     * nacos默认只寻找相同namespace和相同group里的服务实例。本项目需要获取同namespace中不同group     * 里的项目,所以对源码进行改造,能获取不同group下的服务实例。     * @return     */    private List<NacosServer> getServers() {        try {        //TODO 本项目中只获取同namesapce中不同group下服务实例。如果要获取不同namespace,可以调用nacos中提供的获取所有namespace的接口,然后循环遍历即可。           //TODO 需要注意的是,在nacos提供的open api中,并没有获取所有分组group的方法,因此,我们只能自己去维护我们的项目里定义了哪些分组,然后手动获取这些分组下的服务实例。           //获取master分组服务实例            List<Instance> instances1 = discoveryProperties.namingServiceInstance()                    .selectInstances(serviceId,"master", true);                    //获取slave分组服务实例            List<Instance> instances2 = discoveryProperties.namingServiceInstance()                    .selectInstances(serviceId,"slave", true);            List<Instance> instances=new ArrayList<>();            instances.addAll(instances1);            instances.addAll(instances2);            //master分组和slave分组实例都加入处理            return instancesToServerList(instances);        }        catch (Exception e) {            throw new IllegalStateException(                    "Can not get service instances from nacos, serviceId=" + serviceId,                    e);        }    }    private List<NacosServer> instancesToServerList(List<Instance> instances) {        List<NacosServer> result = new ArrayList<>();        if (CollectionUtils.isEmpty(instances)) {            return result;        }        for (Instance instance : instances) {            result.add(new NacosServer(instance));        }        return result;    }    @Override    public void initWithNiwsConfig(IClientConfig iClientConfig) {        this.serviceId = iClientConfig.getClientName();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

然后要覆盖NacosRibbonClientConfiguration源码类,将我们自己定义的AppNacosServerList加入其中即可。需要注意的是需要在项目中定义与NacosRibbonClientConfiguration相同的jar包路径,才能覆盖,如下图所示:

当然,可以直接覆盖NacosServerList类也行,这样可以少覆盖一个类。当然大体思路是一致的。

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发