云计算百科
云计算领域专业知识百科平台

Nacos 本地和服务器服务注册隔离

背景

        当本地服务和服务器公用同一个 nacos 时(开发环境),亦或者需要连接测试环境进行问题排查时,我们可能会将本地服务注册到服务器的命名空间,这样会导致服务器的请求会被打到本地。而如果本地代码和服务器的代码不一致,就可能会导致客户端异常问题。

        而如果我们只是简单的把自己的服务注册到自己的命名空间,和服务器命名空间隔离,却又会导致本地服务请求不到服务器命名空间内注册的其他服务。

        网上能找到相关问题的解决方案,比如这篇文章 Nacos服务跨分组调用 就是通过分组隔离,然后重写服务发现策略来进行跨分组服务调用从而解决上述问题的。

        本文会涉及到如何加载自己的配置文件,并且让其优先级高于 bootstrap.yml 等配置文件(也会高于 nacos配置中心 的配置 )

       本文主要讲的只是一种新的解决思路,至少是我没在网上找到的思路。并不是更好。

相关依赖

       springboot:2.7.15

隔离方法

命名空间隔离

          首先,我们需要把我们自己本地的服务注册到自己的命名空间中,这个没什么好说的

请求服务器其他服务的方法 

        通过 FeignClient 注解中的 url  读取配置文件的属性,如下所示

@FeignClient(value = "${server.application1.server-name}", url = "${server.application1.url:}")
public interface ITestFacade {

}

        仅当配置文件中存在该属性时,才会请求该属性对应  url 服务,而属性不存在时,则走项目原来的逻辑 

加载自定义配置文件                

        需要考虑与 spring 原生的配置方式区分开,降低耦合度。且能避免和正式的配置混在一起。具体如下

        配置文件路径的配置方式

        考虑通过命令行的方式传入,可以在 idea 的启动配置中进行如下配置,当没有进行配置时,就会走项目原本的调用逻辑。而该配置只需要在本地环境配置,因此服务器启动的命令不特意加入该配置,就不会对服务器环境产生任何影响。

        a.yml 的配置如下所示

#feign 请求的服务和ip
server:
application1:
server-name: application1
#通过feign请求时需要请求的服务的 url 地址,不配置则feign会走项目原本的逻辑
url: http://192.168.1.1:8080

spring:
cloud:
nacos:
discovery:
#配置自己私有的命名空间
namespace: 8cas0d6r-dax7-467a-9f99-6ed7fcd9f3c8

  配置加载方式

        由于需要配置注册到自己命名空间,且优先级需要高于 bootstrap.yml ,否则配置就无法生效,所以就需要考虑让自己的配置优先级高于  bootstrap.yml ,具体有两种方案

          方案1:

         通过自定义 EnvironmentPostProcessor ,从而在 spring 环境准备好后,加载自己指定的配置文件,并且将其优先级配置的比 bootstrap.yml  高。具体代码如下所示

public class CustomConfigEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
try {
//从java 启动命令行中获取配置文件路径
String fileName = environment.getProperty("customConfig.path");

Resource resource = null;
//优先从项目的classPath读取配置文件(打包前在项目的 resources 文件夹里,打包后读取jar包中的文件)
resource = new ClassPathResource(fileName);
if (!resource.exists()) {
//绝对路径,用绝对路径就可以让多个服务公用一个配置文件(如果时相对路径,打包前是项目最外层pom.xml同目录下的文件,打包后就是jar所在目录)
resource = new FileUrlResource(fileName);
if (!resource.exists()) {
//当配置不存在时,则直接跳过,配置不生效,就会和没进行任何隔离的效果一样
return;
}
}

YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
List<PropertySource<?>> config = loader.load("custom config", resource);
for (PropertySource<?> propertySource : config) {
//addFirst 让优先级最高
// environment.getPropertySources().addFirst(propertySource);
//让优先级比 命令行的args 低一级,但会比bootstrap.yml高和nacos配置中心的配置高
environment.getPropertySources().addAfter("commandLineArgs", propertySource);
}
} catch (IOException e) {
e.printStackTrace();
}
}

}

然后需要在 resources/META-INF 下配置 spring.factories

 

spring.factories 的配置如下所示

org.springframework.boot.env.EnvironmentPostProcessor=\\
com.zzz.CustomConfigEnvironmentPostProcessor

(当然也可以通过监听 ApplicationEnvironmentPreparedEventEvent 或者 SringApplication.prepareContext 环节中的某个环境的扩展点写上面类似的代码实现) 

如果想了解spring 配置的加载流程可以看看这篇文章 nacos bootstrap.yml 和 spring.config.import 加载配置的流程区别

        方案2

        利用命令行方式(main 方法的 args )加载自定义配置,具体代码如下所示

public class TestApplication {
public static void main(String[] args) {
try {
//从java 启动命令行中获取配置文件路径
SimpleCommandLinePropertySource simpleCommandLinePropertySource = new SimpleCommandLinePropertySource(args);
String fileName = simpleCommandLinePropertySource.getProperty("customConfig.path");

Resource resource = null;
//优先从项目的classPath读取配置文件(打包前在项目的 resources 文件夹里,打包后读取jar包中的文件)
resource = new ClassPathResource(fileName);
if (!resource.exists()) {
//绝对路径,用绝对路径就可以让多个服务公用一个配置文件(如果时相对路径,打包前是项目最外层pom.xml同目录下的文件,打包后就是jar所在目录)
resource = new FileUrlResource(fileName);
if (!resource.exists()) {
//当配置不存在时,则直接跳过,配置不生效,就会和没进行任何隔离的效果一样
return;
}
}

YamlPropertiesFactoryBean yamlBean = new YamlPropertiesFactoryBean();
yamlBean.setResources(resource);
Properties properties = yamlBean.getObject();
if (properties.size() > 0) {
List<String> config = new ArrayList<String>();
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
if (simpleCommandLinePropertySource.containsProperty(entry.getKey().toString())) {
//如果命令行中本身就存在参数,就跳过,防止自定义配置文件的配置优先级比命令行高
continue;
}
config.add("–" + entry.getKey() + "=" + entry.getValue());
}
//args 比bootstrap.yml高和nacos配置中心的配置高
args = config.toArray(new String[config.size()]);
}
} catch (IOException e) {
e.printStackTrace();
}

SpringApplication.run(TestApplication.class, args);
}
}

        命令行的配置的优先级本身就比 bootstrap.yml nacos 高。所以不需要额外进行处理

和背景中给出文章的方案对比

        本文的方法其实并不会更好,可能就是配置起来更简单,耦合度更低,简单。

        而背景中的方案是是通过自定义发现策略实现的,更加灵活,可以自定义自己的规则进行不同的负载,比如方案中是可以跨分组请求,但同时也能改成跨命名空间请求,还可以改成根据前端请求头中的参数进行负载。

赞(0)
未经允许不得转载:网硕互联帮助中心 » Nacos 本地和服务器服务注册隔离
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!