我所理解的其他问题·第9篇·由Dubbo直连引出的File路径问题

2020/09/09 Java 共 2566 字,约 8 分钟

本文讲述了 Dubbo 直连的几种实现方式以及我在进行直连调试的时候遇到的几个问题。

others-9-封面

1. Dubbo 直连的几种方式

在 Dubbo 官网的直连提供者这篇文章中向开发者介绍了绕过注册中心,直接通过ip+端口指定服务提供者的直连方式。

需要注意的是:官方建议直连方式仅开发测试时使用!

Dubbo 直连有4种实现方式:

1.1 通过 XML 配置

<dubbo:reference id="xxxService" interface="com.alibaba.XxxService" url="dubbo://localhost:20890" />

1.2 通过注解方式配置

    @Reference(check = false, timeout = 60000, url = "localhost:20890")
    private XxxService xxxService;

1.3 通过 -D 参数指定接口

java -Dcom.alibaba.XxxService=dubbo://localhost:20890 -jar Demo.jar

1.4 通过 -D 参数指定映射文件

java -Ddubbo.resolve.file=xxx.properties  -jar Demo.jar

然后在 xxx.properties 文件中加入如下配置

com.alibaba.xxx.XxxService=dubbo://localhost:20890

2. 直连调试

在项目中有很多个 Dubbo 接口,而且在线上的某种环境中是没有 zk 注册中心的,出于切换 Dubbo 接口调用方式以及方便管理所有 Dubbo 接口的考虑,我选用的是第四种——通过映射文件实现直连。

注意:本项目使用的 Dubbo 版本是2.6.0。

2.1 @Reference注入为null

刚开始调试的时候,我发现在有注册中心的环境下发现在消费者中无法通过 @Reference 注解注入 Dubbo 接口,开始我以为是 Dubbo 版本的问题,后来将生产者与消费者的 Dubbo 版本号改为一致才发现不是这个原因。自己研究了好久,实在找不到原因了于是寻求身为 Dubbo committer 的同事的帮助才知道原来是在启动类中没有配置 @EnableDubboConfiguration 注解启用 Dubbo 导致的,惭愧惭愧。

2.2 映射文件路径问题排查

在解决了上面的问题之后,首先我在消费者的配置文件中将 Spring.dubbo.registry.address 改为 N/A,表明不使用注册中心,然后在 resource 目录下新增映射文件dubbo.properties,同时在映射文件中指定直连接口:

com.alibaba.xxx.XxxService=dubbo://localhost:20891

最后在编译器的 Run/Debug Configuration 中添加如下的启动参数配置:

others-9-1

然后在启动之后却出现了让我差异的报错:

others-9-2

dubbo.properties 文件不存在,开始我以为是 target 目录中没有把这个文件编译进去,因为之前也发生过 idea 编译后某些类和资源文件没有更新的情况,但事实却不是如此,target目录中 dubbo.properties 好端端的在那里。

然后我把编译器 Run/Debug Configuration 配置中的文件名改成了它的绝对路径

-Ddubbo.resolve.file=/Users/fan/workspace/Windfall/src/main/resources/dubbo.properties

发现程序可以正常启动,这样问题就很明显了,绝对是文件路径的锅!

我循着报错的异常栈,在报错的地方打了一个断点进行调试,在新建 FileInputStream 对象打开文件的地方执行了获取 File 对象绝对路径的方法。

others-9-3

dubbo.properties 的绝对路径竟然是这么个玩意,本项目的项目名是 Windfall,相当于程序会从当前工程目录下寻找映射文件,而我创建文件的路径是 Windfall->src->main->resource,这当然会找不到。

于是我把启动参数改成了:

-Ddubbo.resolve.file=src/main/resources/dubbo.properties

果然,在编译器中程序正常启动了。

问题就这样解决了,但是让我疑惑的是,为什么我指定了映射文件名之后,它的路径却变成了从当前工程目录下进行寻找。然后我翻了翻 File#getAbsolutePath() 方法,发现这个方法中执行的逻辑其实是这样的:

public String resolve(File f) {
    if (isAbsolute(f)) return f.getPath();
    return resolve(System.getProperty("user.dir"), f.getPath());
}

如果文件本来就是以绝对路径创建的,直接返回它的 path,否则在 path 前加上 user.dir 作为该文件的绝对路径,而 user.dir 环境变量就是指用户当前工作目录。

2.3 关于 user.dir

还有需要注意的是,在命令行中启动 jar 包,user.dir 的路径就是执行启动命令的目录。

为此,我写了一个测试程序。

public class demo{
    public static void main(String[] args) {
        System.out.println(System.getProperties("user.dir"));
    }
}

先用 javac demo.java 命令编译程序,然后执行java demo命令启动程序,打印 user.dir 的信息,我在多个目录中都尝试了这个程序,发现输出的结果都不相同。

others-9-4

从程序执行的结果来看,user.dir 的结果就是执行启动命令的路径。所以,在服务器上使用 Dubbo 进行直连的时候,需要注意 dubbo.properties 文件需要放在执行启动脚本的目录。

3. 小结

本文讲述了 Dubbo 直连的几种实现方式以及我在进行直连调试的时候遇到的几个问题:

  • @EnableDubboConfiguration 注解启用 Dubbo
  • new File() 路径问题
  • user.dir 值问题

4. 参考资料

最后,本文收录于个人语雀知识库: 我所理解的后端技术,欢迎来访。

文档信息

Search

    Table of Contents