5.3.2 依賴編譯型語言的Java應用遷移
對于大型項目來說,很多時候不僅僅使用一種語言來開發應用,有時候會使用多種語言進行混合編程,例如著名的開源項目Netty,主體開發語言是Java,但是在部分項目里還使用了C語言。出現這種情況的一個原因是Netty在Linux下的異步/非阻塞網絡傳輸中,使用了Epoll——一個基于I/O事件通知的高性能多路復用機制。Netty是通過JNI方式提供Native Socket Transport的,在Netty的transport-native-epoll項目中,有相關調用的C代碼。
除此之外,在Netty的依賴項目netty-tcnative-parent中,也有JNI方式提供的C語言調用。
筆者負責的一款基于Java的物聯網平臺中也使用了Netty,在進行應用遷移時經過多次嘗試,解決了多個問題,最后遷移成功,這里通過Netty項目,演示一下依賴編譯型語言的Java應用的遷移。
1.遷移過程分析
Netty是開源的項目,在獲得所有的源代碼后,可以通過對代碼進行重新編譯的方式來執行遷移。因為代碼里有Java和C語言,并且Netty項目是通過Pom進行項目組織管理的,在遷移時不但要安裝C的編譯環境,還要安裝openjdk和Maven。
2.安裝依賴項
要安裝的依賴項較多,大部分可以通過yum安裝,命令如下:
yum install gcc gcc-c++ make cmake3 libtool autoconf automake ant wget git openssl openssl - devel apr-devel ninja-build java-1.8.0-openjdk.aarch64 – y
安裝依賴項的時間有點長,根據系統中已安裝的軟件情況,可能需要幾分鐘到十幾分鐘,最后回顯如下:

因為后續步驟在編譯libressl-static模塊的時候需要cmake版本號大于3,并且需要ninja,這里提前做好軟連接,命令如下:
ln -s /usr/bin/cmake3 /usr/bin/cmake ln -s /usr/bin/ninja-build /usr/bin/ninja
3.安裝Maven
Java應用的編譯打包需要Maven,安裝步驟如下:
步驟1:下載Maven 3.6.3安裝包,為了提高下載速度,可以使用國內的下載源,命令如下:
wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven - 3/3.6.3/binaries/apache - maven-3.6.3 -bin.tar.gz
步驟2:解壓Maven安裝包,命令如下:
tar -zvxf apache-maven-3.6.3 -bin.tar.gz
步驟3:移動Maven到指定目錄,命令如下:
mv apache-maven-3.6.3 /opt/tools/
步驟4:配置環境變量,修改/etc/profile文件,在文件最后增加Maven的環境信息,增加的內容如下:
MAVEN_HOME=/opt/tools/apache-maven-3.6.3 PATH= $ MAVEN_HOME/bin:$ JAVA_HOME/bin: $ PATH export MAVEN_HOME JAVA_HOME PATH
步驟5:使環境變量生效,命令如下:
source /etc/profile
步驟6:由于Maven中央倉庫的下載速度受限,所以這里配置Maven的鏡像倉庫網址為國內的鏡像,要修改的配置文件路徑為/opt/tools/apache-maven-3.6.3/conf/settings.xml,在該文件的<mirrors>節中添加新的鏡像,添加的內容如下:

步驟7:查看Maven是否安裝成功,命令及回顯如下:

如果出現類似上面的回顯,表示Maven安裝配置成功了。
4.處理鯤鵬架構中char類型為無符號型的默認設置
直接對代碼中char類型進行更改風險較高,工作量也很大,這里通過設置gcc和g++的編譯選項來處理,也就是把這兩個編譯器的編譯加上-fsigned-char的選項。
1)修改gcc編譯選項
步驟1:確認gcc的位置,命令及回顯如下:
[root@ecs-kunpeng ~]#command -v gcc /usr/bin/gcc
根據系統不同,位置可能有差異,筆者本機的位置在/usr/bin/gcc。
步驟2:修改gcc的名字為gcc-ori,命令如下:
mv/usr/bin/gcc /usr/bin/gcc-ori
步驟3:創建/usr/bin/gcc文件,命令如下:
vi /usr/bin/gcc
步驟4:編輯/bin/gcc文件,輸入內容如下:
#! /bin/sh /usr/bin/gcc-ori -fsigned-char "$@"
步驟5:給/bin/gcc添加執行權限,命令如下:
chmod +x /usr/bin/gcc
步驟6:查看gcc是否可以成功執行,命令及回顯如下:
[root@ecs-kunpeng ~]#gcc --version gcc-ori (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44) Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
如果看到類似上面的回顯,表示gcc修改成功了。
2)修改g++編譯選項
步驟1:確認g++的位置,命令及回顯如下:
[root@ecs-kunpeng ~]#command -v g++ /usr/bin/g++
本機位置是/usr/bin/g++,不同的服務器位置可能不同。
步驟2:修改g++的名字為g++-ori,命令如下:
mv /usr/bin/g++ /usr/bin/g++ -ori
步驟3:創建/usr/bin/g++文件,命令如下:
vi /usr/bin/g++
步驟4:編輯/bin/g++文件,輸入內容如下:
#! /bin/sh /usr/bin/g++ -ori -fsigned-char "$@"
步驟5:給/bin/g++添加執行權限,命令如下:
chmod +x /usr/bin/g++
步驟6:查看g++是否可以成功執行,命令及回顯如下:
[root@ecs-kunpeng ~]#g++ --version g++ -ori (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44) Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
如果看到類似上面的回顯,表示g++修改成功了。
5.加速編譯準備
在正式編譯以前,需要先下載3個安裝包。后面的編譯過程需要從多個網站下載安裝包,這些網站的服務器一般都在境外,下載速度較慢,可能會因為下載不成功導致編譯失敗。
步驟1:下載apr-1.6.5,進入/data/soft/文件夾,下載命令如下:
wget https://mirrors.tuna.tsinghua.edu.cn/apache/apr/apr-1.6.5.tar.gz
步驟2:下載libressl-3.1.1,下載命令如下:
wget https://mirrors.tuna.tsinghua.edu.cn/OpenBSD/LibreSSL/libressl-3.1.1.tar.gz
步驟3:下載openssl-1.1.1g,下載命令如下:
wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz
6.編譯netty-tcnative-2.0.34
步驟1:進入/data/soft/下載netty-tcnative源碼包,下載命令如下:
wget https://GitHub.com/netty/netty - tcnative/archive/netty - tcnative - parent - 2.0.34. Final.tar.gz
步驟2:解壓源碼包,并進入解壓后目錄,命令如下:
tar -zxvf netty-tcnative-parent-2.0.34.Final.tar.gz cd netty-tcnative-netty-tcnative-parent-2.0.34.Final/
步驟3:修改pom文件,注釋掉對apr的下載,對于2.0.34版本來說,注釋行在第474行,修改后的該段配置如下:

注釋掉該行后,mvn編譯時將不再從這里下載。
步驟4:進入libressl-static目錄,修改pom文件,注釋掉對libssl的下載,注釋行在第263行,修改后的該段配置如下:

步驟5:進入openssl-static目錄,修改pom文件,注釋掉對openssl的下載,注釋行在第334行和第338行,修改后的該段配置如下:

步驟6:注釋掉對boringssl-static的編譯(在第603行),因為boringssl-static需要從谷歌服務器獲取資源,由于無法獲取成功,這里就取消對它的編譯,但不影響后續的使用(如果確實要用,可以把獲取源碼網址改為GitHub上的源碼網址,這里就不演示了)。編輯源代碼主目錄的pom文件,修改后的該段配置如下:

步驟7:提前創建好openssl-static和libressl-static項目的target目錄,命令如下:
mkdir /data/soft/netty- tcnative-netty- tcnative-parent- 2.0.34.Final/openssl - static/ target/ mkdir /data/soft/netty- tcnative-netty- tcnative-parent- 2.0.34.Final/libressl - static/ target/
步驟8:復制預先下載的文件到target目錄,命令如下:
cp /data/soft/apr-1.6.5.tar.gz /data/soft/netty-tcnative-netty-tcnative-parent-2.0. 34.Final/openssl-static/target/ cp /data/soft/openssl-1.1.1g.tar.gz /data/soft/netty-tcnative-netty-tcnative-parent- 2.0.34.Final/openssl-static/target/ cp /data/soft/apr-1.6.5.tar.gz /data/soft/netty-tcnative-netty-tcnative-parent-2.0. 34.Final/libressl-static/target/ cp /data/soft/libressl-3.1.1.tar.gz /data/soft/netty-tcnative-netty-tcnative-parent- 2.0.34.Final/libressl-static/target/
步驟9:進入主目錄,執行編譯,命令如下:
cd /data/soft/netty-tcnative-netty-tcnative-parent-2.0.34.Final/ mvn install
最后編譯成功的回顯如下:

7.編譯netty-all-4.1.52
步驟1:進入/data/soft/下載netty-all源碼包,下載命令如下:
wget https://GitHub.com/netty/netty/archive/netty-4.1.52.Final.tar.gz
步驟2:解壓源碼包,并進入解壓后目錄,命令如下:
tar -zxvf netty-4.1.52.Final.tar.gz cd netty-netty-4.1.52.Final/
步驟3:處理jni.h問題。在后續的編譯中,可能會出現找不到jni.h和jni_md.h的錯誤,如圖5-9所示。

圖5-9 編譯錯誤
出現這種錯誤的原因是C編譯器找不到頭文件的位置,所以需要直接告訴編譯器頭文件在哪里,就是通過C編譯器選項CFLAGS傳過去頭文件的路徑。本機的jni.h文件在/usr/lib/jvm/java/include目錄下,jni_md.h文件在/usr/lib/jvm/java/include/Linux/目錄下。編輯transport-native-UNIX-common下的pom文件,命令如下:
vim /data/soft/netty-netty-4.1.52.Final/transport-native-UNIX-common/pom.xml
要修改的CFLAGS選項在第198行和第263行,在值的后面加上頭文件的位置,代碼如下:
-I/usr/lib/jvm/java/include -I/usr/lib/jvm/java/include/Linux/
修改后的效果如下所示,注意修改后的字符串也是全部在value值的引號里面,代碼如下:

步驟4:編譯netty-all,進入源碼主目錄,執行編譯,命令如下:
mvn install -DskipTests
該命令將跳過測試過程,經過十幾分鐘的編譯后,可以看到成功編譯的回顯如下所示:



鯤鵬架構的jar包就在各個項目的target目錄下,例如transport-native-epoll項目下的jar包,顯示如下:

包含aarch_64的jar包就是鯤鵬架構下適用的jar包。
- C#高級編程(第10版) C# 6 & .NET Core 1.0 (.NET開發經典名著)
- GAE編程指南
- Arduino開發實戰指南:LabVIEW卷
- Ray分布式機器學習:利用Ray進行大模型的數據處理、訓練、推理和部署
- aelf區塊鏈應用架構指南
- Python機器學習編程與實戰
- 程序是怎樣跑起來的(第3版)
- Spring核心技術和案例實戰
- Python算法詳解
- Mastering C++ Multithreading
- Java Web應用開發給力起飛
- CodeIgniter Web Application Blueprints
- 邊玩邊學Scratch3.0少兒趣味編程
- Offer來了:Java面試核心知識點精講(框架篇)
- RESTful Web API Design with Node.js(Second Edition)