SpringCloud-Nacos跨组服务调用
沙福林 2025-04-29 22:05:09
SpringCloud
nacos
场景:有一个网关入口,在网关的方法里,需要调用其他微服务的接口,A,B,C 是我们的服务,D,E 是其他项目组的服务,在我们的微服务A,B,C里有可能要调用其他项目组的服务。
- A,B,C 是我们的服务注册到nacos默认的
命名空间->组->服务名下 - D,E 服务注册到nacos默认的
命名空间->组->服务名下
# 场景
有一个网关入口,在网关的方法里,需要调用其他微服务的接口,A,B,C 是我们的服务,D,E 是其他项目组的服务,在我们的微服务A,B,C里有可能要调用其他项目组的服务。
- A,B,C 是我们的服务注册到nacos默认的
命名空间->组->服务名下 - D,E 服务注册到nacos默认的
命名空间->组->服务名下
# 问题
- 如果本地开发时,我们的服务使用同样的
命名空间->组->服务名,那肯定会影响线上服务的正常调用。 - 如果本地开发时,不使用
D,E服务的命名空间->组->服务名,就没有办法调用到该服务 - 如果本地开发时,使用
D,E服务的命名空间->组->服务名,但是由于D,E的开发人员节点也注册上去,从而调用到他们的服务,从而导致项目组服务调用失败。
# 思考
- 服务调用默认都是按
命名空间->组->服务名查找的,如果我的服务在自己的组里,那么就不会影响线上服务的正常调用。 - 如果我能跨组调用服务,那么我即便在自己的组下,也能调用到其他项目组的服务。
- 在跨组调用基础上,如果我能有限筛选服务示例对应的ip,那么我既能跨组调用到其他项目组的服务,又能保证我调用到的服务节点是服务器的,而不是某开发本地的。
- 与线上服务公用一个nacos服务,本地少起一个服务不香吗
- 如果我能跨组调用服务,那么我本地的很多服务就不用自己启动了
# 1.增加配置类
- NacosDiscoveryAutoConfigurationV2
package com.sxszck.shafulin.config.nacos;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 参考文档 https://blog.csdn.net/m0_56287495/article/details/129240577
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
@AutoConfigureBefore({NacosDiscoveryAutoConfiguration.class})
public class NacosDiscoveryAutoConfigurationV2 {
@Bean
@ConditionalOnMissingBean
public NacosServiceDiscovery nacosServiceDiscovery(NacosDiscoveryProperties nacosDiscoveryProperties, NacosServiceManager nacosServiceManager) {
return new NacosServiceDiscoveryV2(nacosDiscoveryProperties, nacosServiceManager);
}
}
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
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
- NacosServiceDiscoveryV2
package com.sxszck.shafulin.config.nacos;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceInstance;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.cloud.client.ServiceInstance;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 参考文档 https://blog.csdn.net/m0_56287495/article/details/129240577
*/
public class NacosServiceDiscoveryV2 extends NacosServiceDiscovery {
/**
* 优先选择服务器ip
*/
public static final Map<String,List<String>> IP_MAP = new HashMap<>();
static {
// D 服务
IP_MAP.put("D-server", Arrays.asList("10.12.18.165"));
// E 服务
IP_MAP.put("E-server", Arrays.asList("10.12.18.173"));
}
public NacosServiceDiscoveryV2(NacosDiscoveryProperties discoveryProperties, NacosServiceManager nacosServiceManager) {
super(discoveryProperties, nacosServiceManager);
this.discoveryProperties = discoveryProperties;
this.nacosServiceManager = nacosServiceManager;
}
private NacosDiscoveryProperties discoveryProperties;
private NacosServiceManager nacosServiceManager;
//
@Override
public List<ServiceInstance> getInstances(String serviceId) throws NacosException {
String group = this.discoveryProperties.getGroup();
// 优先保证同分组下的服务调用
List<Instance> instances = this.namingService().selectInstances(serviceId, group, true);
if (CollectionUtils.isEmpty(instances)) {
// 如果同分组下找不到服务,那么就从默认分组下找服务
instances = this.namingService().selectInstances(serviceId, "DEFAULT_GROUP", true);
}
if (IP_MAP.containsKey(serviceId)) {
List<String> ipList = IP_MAP.get(serviceId);
List<Instance> newInstances = instances.stream()
.filter(item -> ipList.contains(item.getIp()))
.collect(Collectors.toList());
// 能查到服务器的ip,那么就返回
if (CollectionUtils.isNotEmpty(newInstances)){
return hostToServiceInstanceList(newInstances, serviceId);
}
}
return hostToServiceInstanceList(instances, serviceId);
}
@Override
public List<String> getServices() throws NacosException {
String group = this.discoveryProperties.getGroup();
ListView<String> services = this.namingService().getServicesOfServer(1, Integer.MAX_VALUE, group);
return services.getData();
}
public static List<ServiceInstance> hostToServiceInstanceList(List<Instance> instances, String serviceId) {
List<ServiceInstance> result = new ArrayList(instances.size());
Iterator var3 = instances.iterator();
while (var3.hasNext()) {
Instance instance = (Instance) var3.next();
ServiceInstance serviceInstance = hostToServiceInstance(instance, serviceId);
if (serviceInstance != null) {
result.add(serviceInstance);
}
}
return result;
}
public static ServiceInstance hostToServiceInstance(Instance instance, String serviceId) {
if (instance != null && instance.isEnabled() && instance.isHealthy()) {
NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
nacosServiceInstance.setHost(instance.getIp());
nacosServiceInstance.setPort(instance.getPort());
nacosServiceInstance.setServiceId(serviceId);
nacosServiceInstance.setInstanceId(instance.getInstanceId());
Map<String, String> metadata = new HashMap();
metadata.put("nacos.instanceId", instance.getInstanceId());
metadata.put("nacos.weight", instance.getWeight() + "");
metadata.put("nacos.healthy", instance.isHealthy() + "");
metadata.put("nacos.cluster", instance.getClusterName() + "");
if (instance.getMetadata() != null) {
metadata.putAll(instance.getMetadata());
}
metadata.put("nacos.ephemeral", String.valueOf(instance.isEphemeral()));
nacosServiceInstance.setMetadata(metadata);
if (metadata.containsKey("secure")) {
boolean secure = Boolean.parseBoolean((String) metadata.get("secure"));
nacosServiceInstance.setSecure(secure);
}
return nacosServiceInstance;
} else {
return null;
}
}
private NamingService namingService() {
return this.nacosServiceManager.getNamingService();
}
}
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# 2.给服务启动器添加命令行传参
为什么要用这种方式传参呢?
- 优先级最高容易生效
- 不会修改代码配置文件,避免被版本控制提交
- 不会修改代码,避免被版本控制提交
- 配置文件不做任何更改

- 编辑启动器

- 覆盖配置(即命令行传参)

- 覆盖参数
属性名:spring.cloud.nacos.discovery.group,属性值:自己的姓名 - 启动服务
# 3.查看Nacos上的服务
在服务列表能看到你的服务,即启动成功

# 4.验证方式
启动网关服务,如果你的服务调用顺序是
- 情况1: 网关服务->服务A/B/C,服务D/E (只启动
网关服务即可) - 情况2: 网关服务->服务A->服务B,服务D/E (只启动
网关,A服务即可)
结论:总之,如果你只是调用某个外部服务,外部服务的调用方也必须启动,不然调用不到你本地