mochiweb 源碼閱讀(二)


  大家好,幾天沒跟新了,在上一篇,我們簡單介紹了mochiweb這個項目,以及下載,編譯,創建mochiweb的源碼以及示例。今天繼續跟大家來分析mochiweb這個項目,跟之前分析cowboy的方法一樣,我們找到切入口點,來一一分析每個函數的功能,作用,下面看下上一篇創建的示例都有哪些文件,如下圖:

  

  這里除了keepalive.erl 是我從官方example考過來以外,其他為上一篇創建的例子的源碼。

  我不一一介紹這幾個文件了,參考我一直給大家推薦的Erlang OTP 設計原理。好好看幾遍,你就對Erlang應用程序有一定的了解了。

  我們從運行程序的 mochiweb_example:start/0 開始看吧,代碼如下:

%% @spec start() -> ok
%% @doc Start the mochiweb_example server.
start() ->
    mochiweb_example_deps:ensure(),
    ensure_started(crypto),
    application:start(mochiweb_example).

  這個函數三行代碼,第一行先跳過,一會我們重點看下。

  第二行啟動crypto,mochiweb_example:ensure_started/1,代碼如下:

ensure_started(App) ->
    case application:start(App) of
        ok ->
            ok;
        {error, {already_started, App}} ->
            ok
    end.

  很簡單,判斷下該應用程序是否啟動,如果沒啟動就啟動,如果已經啟動了,就提示 {error, {already_started, App}} 錯誤。

  第三行,啟動mochiweb_example,很簡單,其實這里也可以修改成這樣:ensure_started(mochiweb_example),因為上面那個函數本來也就是啟動應用程序用的。不知道作者為什么生成代碼,不用上面的函數,不過關系不大。

  現在可以重點看下:mochiweb_example_deps:ensure/0 這個函數了,代碼如下:

%% @spec ensure(Module) -> ok
%% @doc Ensure that all ebin and include paths for dependencies
%%      of the application for Module are on the code path.
ensure(Module) ->
    code:add_paths(new_siblings(Module)),
    code:clash(),
    ok.

%% @spec ensure() -> ok
%% @doc Ensure that the ebin and include paths for dependencies of
%%      this application are on the code path. Equivalent to
%%      ensure(?Module).
ensure() ->
    ensure(?MODULE).

  從上面代碼可以知道 mochiweb_example_deps:ensure/0 調用 mochiweb_example_deps:ensure/1 函數,並傳遞參數 ?MODULE,而mochiweb_example_deps:ensure/1 函數,就三行代碼也很簡單,我們先看下 mochiweb_example_deps:new_siblings/1 函數:

%% @spec new_siblings(Module) -> [Dir]
%% @doc Find new siblings paths relative to Module that aren't already on the
%%      code path.
new_siblings(Module) ->
    Existing = deps_on_path(),
    SiblingEbin = filelib:wildcard(local_path(["deps", "*", "ebin"], Module)),
    Siblings = [filename:dirname(X) || X <- SiblingEbin,
                           ordsets:is_element(
                             filename:basename(filename:dirname(X)),
                             Existing) =:= false],
    lists:filter(fun filelib:is_dir/1,
                 lists:append([[filename:join([X, "ebin"]),
                                filename:join([X, "include"])] ||
                                  X <- Siblings])).

  從這個函數的注釋,我們能大概知道,查找相對於Module模塊不在代碼路徑下的新的路徑。看下具體邏輯,首先是 mochiweb_example_deps:deps_on_path/0 函數,代碼如下:

%% @spec deps_on_path() -> [ProjNameAndVers]
%% @doc List of project dependencies on the path.
deps_on_path() ->
    F = fun (X, Acc) ->
                ProjDir = filename:dirname(X),
                case {filename:basename(X),
                      filename:basename(filename:dirname(ProjDir))} of
                    {"ebin", "deps"} ->
                        [filename:basename(ProjDir) | Acc];
                    _ ->
                        Acc
                end
        end,
    ordsets:from_list(lists:foldl(F, [], code:get_path())).

  這個函數,有不少的系統函數,我們先看下這幾個函數:

  函數:filename:dirname/1,返回當前文件名所在的目錄,大家可以查下erlang doc,地址:http://www.erlang.org/doc/man/filename.html#dirname-1 我截了個圖,方便大家看吧,如下圖:

  函數filename:basename/1,大概意思是:如果它不包含任何目錄分隔符,返回最后一部分的文件名或文件名本身。同樣查下erlang doc,地址:http://www.erlang.org/doc/man/filename.html#basename-1,如下圖:

  函數:code:get_path/0,返回當前代碼路徑。 erlang doc 地址:http://www.erlang.org/doc/man/code.html#get_path-0,如下圖:

  

  我在shell上嘗試打印出完整的列表(使用rp命令),一共是58項,如下圖:

  

  

  函數:lists:foldl/3,對List中的每一項執行函數Fun,Acc0作為該函數第二個參數。 erlang doc 地址:http://www.erlang.org/doc/man/lists.html#foldl-3,如下圖:

  我們做個練習如下:

  

  函數: ordsets:from_list/1,對List排序,erlang doc 地址:http://www.erlang.org/doc/man/ordsets.html#from_list-1,如下圖:

   示例如下:

  

  理解完這幾個系統函數,我們來整理下 mochiweb_example_deps:deps_on_path/0 這個函數的作用。首先是定義了匿名函數F,接受2個參數,X為調用 code:get_path/0 返回的列表的每一項項,Acc用來保存對每一項處理的結果。而處理每一項的邏輯也很簡單,這里我們用Debugger跟蹤下其中一項的處理過程,如下圖:

  圖一:

  

  圖二:

  

  圖三:

  

  根據上面三個圖,我們就能更加清楚這個函數的作用了。

  好了,這一篇就到這里,這些系統函數需要多動手練習還會熟悉。希望大家也多多動手,下一篇,我們繼續從mochiweb_example_deps:new_siblings/1 函數往下看。

  謝謝大家的收看。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM