在 Apple M1 (arm处理器) 上构建 netty_transport_native_kqueue_aarch_64 并使用

0x00 背景

当我在 M1(arm处理器)上进行开发的时候,需要用到 netty,尤其是使用它的 Unix Domain Socket 功能,于是在 pom.xml 中有这样的定义

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-transport-native-kqueue</artifactId>
            <classifier>osx-x86_64</classifier>
        </dependency>
复制代码

这会在项目中引入 netty-transport-native-kqueue-4.1.63.Final-osx-x86_64.jar,项目启动回失败,异常日志如下

Caused by: java.lang.IllegalArgumentException: Unsupported channel type: ServerDomainSocketChannel
	at reactor.netty.resources.DefaultLoopNIO.getChannel(DefaultLoopNIO.java:50) ~[reactor-netty-core-1.0.6.jar:1.0.6]
	at reactor.netty.resources.LoopResources.onChannel(LoopResources.java:214) ~[reactor-netty-core-1.0.6.jar:1.0.6]
复制代码

0x01 分析

异常来自如下代码

	public <CHANNEL extends Channel> CHANNEL getChannel(Class<CHANNEL> channelClass) {
		if (channelClass.equals(SocketChannel.class)) {
			return (CHANNEL) new NioSocketChannel();
		}
		if (channelClass.equals(ServerSocketChannel.class)) {
			return (CHANNEL) new NioServerSocketChannel();
		}
		if (channelClass.equals(DatagramChannel.class)) {
			return (CHANNEL) new NioDatagramChannel();
		}
		throw new IllegalArgumentException("Unsupported channel type: " + channelClass.getSimpleName());
	}
复制代码

这段代码在 DefaultLoopNIO 里,继承自 DefaultLoop,DefaultLoop 的实现类还有 DefaultLoopKQueue,按理说, netty 会判断所在的系统来使用 DefaultLoop 的实现类,比如 macos 系统 使用 DefaultLoopKQueue,linux 系统使用 DefaultLoopEpoll。

我用的是 macos 系统,所以代码应该走入到 DefaultLoopKQueue,而不是 DefaultLoopNIO,带着这个问题追踪溯源

原来是 netty 在启动的时候,进行了如下判断

//代码位于 PlatformDependent 类中
private static final String NORMALIZED_ARCH = normalizeArch(SystemPropertyUtil.get("os.arch", ""));
// 在 arm64 机器上,NORMALIZED_ARCH = aarch_64
……
public static String normalizedArch() {
	return NORMALIZED_ARCH;
}
复制代码

经由 Native#loadNativeLibrary 函数中调用 PlatformDependent.normalizedArch() 判断所处操作系统类型

image-20210514225114079.png

然后从Native#loadNativeLibrary 到 NativeLibraryLoader#load() 函数,最终拼接出在 macos(arm64) 平台上应该需要使用的的 jnilib 的名字,libnetty_transport_native_kqueue_aarch_64.jnilib,然后在工程定义的搜索文件路径中搜索该文件。

image-20210514225607800.png

当然找不到了,因为我引入的是 netty-transport-native-kqueue-osx_x86_64 这个 jar,里面携带的 jnilib 文件名字是libnetty_transport_native_kqueue_x86_64.jnilib

image-20210514230225063.png

所以我以为在 pom.xml 中声明一下正确的依赖就可以了

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-transport-native-kqueue</artifactId>
            <classifier>osx-aarch_64</classifier>
        </dependency>
复制代码

0x02 解决

可问题是,maven center 的 release 和snapshot 库都没有 netty-transport-native-kqueue-osx_aarch_64 这个 jar,无奈,心里一横,只能尝试自己去编译这个 jar。

受到 netty-transport-native-epoll-4.1.43.Final-linux-aarch_64.jar 移植指南(CentOS 7.6) 这个启发,于是决定在 macos(arm64) 机器上编译出 netty-transport-native-kqueue-osx_aarch_64,实施步骤和这个文档描述的一样,只是编译第二步的命令需要从 ./mvnw clean install -pl transport-native-epoll -DskipTests=true 替换成 ./mvnw clean install -pl transport-native-kqueue -DskipTests=true

编译成功之后,果然编译出了 netty-transport-native-kqueue-4.1.63.Final-osx-aarch_64.jar,下一步是怎么引入到自己的工程里了。编译结果如下

image-20210514232235263.png

参考 springboot导入本地jar包,我选择将 jar 包放入项目目录中。

首先在src下建目录lib,并将编译好的 netty-transport-native-kqueue-4.1.63.Final-osx-aarch_64.jarnetty-transport-native-kqueue-4.1.63.Final.jar 包放入 lib 文件夹中,然后在 IDEA 的 Libraries 中添加这个 lib 文件夹

image-20210514231617484.png

最后修改 pom.xml

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-transport-native-kqueue</artifactId>
            <classifier>osx-aarch_64</classifier>
            <version>4.1.63.Final</version>
        </dependency>
复制代码

启动工程,可以很顺利地启动了。

0x03 尾声

这只是临时方案,希望 netty 官方尽快发布 netty-transport-native-kqueue-4.1.63.Final.jar 到 maven center。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享