本人第一次用markdown畫流程圖,而且還有點小複雜,上圖將就着看吧,結合代碼理解起來相對簡單。。 上圖的流程主要體現的是hadoop fs xxx
提交到集羣后執行的邏輯,當然這裏主要是進入具體代碼後的邏輯,進入代碼前,以上命令主要是調用的$HADOOP_HOME/bin hadoop
這個腳本,通過這個腳本里面邏輯是:
if [ "$COMMAND" = "fs" ] ; then
CLASS=org.apache.hadoop.fs.FsShell
...
exec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS $CLASS "$@"
顯然通過hadoop fs xxx
調用腳本的時候,後面的fs
和xxx
均是腳本的參數,只是第一個fs
是腳本運行判斷調用哪塊邏輯的參數,而後面的參數xxx
中則是用於給具體java執行類(這裏是FsShell
)的參數。
上圖流程是hadoop fs xxx
這一系列命令提交執行的基本流程,這一塊中涉及到的處理類主要都是繼承自Command.java
,主要涉及類的作用如下:
FsShell.java 業務入口
CommandFactory.java 各種不同類型請求的處理類工廠
Command.java FsCommand的父類,是一個抽象類
FsCommand.java 抽象類,代碼註釋說的很清楚:Base class for all "hadoop fs" commands 所有類型請求均繼承自它
PathData.java 文件系統中某個路徑對應的邏輯實體類,封裝了這個路徑所屬文件系統信息、路徑信息、路徑下的文件信息以及文件是否存在等
以上是一些針對hadoop fs
整體處理邏輯設計的基礎類,對於具體的請求類型常用的如:get
、ls
、put
、rm
等命令,處理類可以在FsCommand.java
的registerCommands
方法中查看到往工廠中註冊的類:
factory.registerCommands(AclCommands.class);
factory.registerCommands(CopyCommands.class);
factory.registerCommands(Count.class);
factory.registerCommands(Delete.class);
factory.registerCommands(Display.class);
factory.registerCommands(FsShellPermissions.class);
factory.registerCommands(FsUsage.class);
factory.registerCommands(Ls.class);
factory.registerCommands(Mkdir.class);
factory.registerCommands(MoveCommands.class);
factory.registerCommands(SetReplication.class);
factory.registerCommands(Stat.class);
factory.registerCommands(Tail.class);
factory.registerCommands(Test.class);
factory.registerCommands(Touch.class);
factory.registerCommands(SnapshotCommands.class);
factory.registerCommands(XAttrCommands.class);
}
對於開篇的流程圖中,每個不同的業務處理類,主要核心的處理邏輯都在processPath(PathData src)
方法中,其它的方法主要是一些流程控制、驗證以及異常處理等,這裏我們挑選get
方法對應的CopyCommands.class
進行介紹,這個CopyCommands.class
類是對於文件複製類命令的合集,其中有registerCommands
,這個方法主要就是註冊各類需要處理的類到工廠類中(存在工廠類中的一個HashMap
中,後續需要用時直接通過命令行參數如get
字符串進行map.get()
獲取),其調用順序是FsShell::run
->FsShell::init
->FsShell::registerCommands
->CommandFactory::registerCommands
,在工廠類CommandFactory::registerCommands
中通過反射調用FsShell::registerCommands
中入參FsCommand
的registerCommands
方法,這個方法也是通過反射的方式調用各個入參類中的registerCommands
方法,這就是CopyCommands.class
中registerCommands
調用的路徑,其它處理類調用註冊邏輯一樣。
繼續來看CopyCommands.class
,其中除了registerCommands
,主要就是提供了七個靜態公共類,我們這裏對於get
請求,處理類就是Get.class
,繼承了一個類叫CommandWithDestination
,這裏查看Get.class
的代碼,只是實現了processOptions
對參數進行設置,核心邏輯在它的父類中,繼續進入父類CommandWithDestination
中,發現父類果然是繼承自FsCommand
,這裏主要看它的核心處理方法processPath
,調用順序:processPath(PathData src)
->processPath(PathData src, PathData dst)
->copyFileToTarget(PathData src, PathData target)
,到了copyFileToTarget
方法這裏的話,邏輯就十分明瞭了,貼出該部分代碼:
throws IOException {
final boolean preserveRawXattrs =
checkPathsForReservedRaw(src.path, target.path);
src.fs.setVerifyChecksum(verifyChecksum);
InputStream in = null;
try {
in = src.fs.open(src.path);
copyStreamToTarget(in, target);
preserveAttributes(src, target, preserveRawXattrs);
} finally {
IOUtils.closeStream(in);
}
}
該部分代碼先獲取了系統設置目標路徑下是否需要保存源文件的元數據信息(例如創建時間、所屬用戶、所屬用戶組等),然後獲取源文件的輸出流,並調用copyStreamToTarget
方法將輸出流中內容寫入到目標路徑中,最後再調用preserveAttributes
進行基本信息元數據信息的填充。
參考文章:
https://blog.csdn.net/strongyoung88/article/details/68952248