在Erlang/OTP ,Application表示作为一个单元,可以启动和停止,执行一些特定功能的组件,并可以在其它系统中重新使用。Application控制器的模块接口,是在每一个Erlang运行时系统启动的进程,并包含用于控制Application(例如启动和停止Application),以及访问Application的信息(例如配置参数)的功能。
Erlang/OTP Application基本结构:
一个 Application 至少包含了3部分的内容:应用模块、监督者模块、资源文件。
应用模块(test_app.erl) :
- -module(test_app).
- -behaviour(application).
- -export([start/2, stop/1]).
- start(_Type, StartArgs) ->
- io:format("test app start~n"),
- case test_sup:start_link(StartArgs) of
- {ok, Pid} ->
- {ok, Pid};
- Error ->
- Error
- end.
- stop(_State) ->
- ok.
监督者模块(test_sup.erl):
- -module(test_sup).
- -behaviour(supervisor).
- -export([start_link/1, init/1]).
- start_link(_) ->
- io:format("test sup start link~n"),
- supervisor:start_link({local, ?MODULE}, ?MODULE, []).
- init([]) ->
- io:format("test sup init~n"),
- {ok,{
- {one_for_one, 1, 60},
- []}
- }.
资源文件(test.app) :
- {application,test,
- [{description,"Test application"},
- {vsn,"1.0.0"},
- {modules,[test_app,test_sup]},
- {registered,[test_app]},
- {mod,{test_app,[]}},
- {env,[]},
- {applications,[kernel,stdlib]}]}.
erl编译以上代码后,执行命令启动这个Application
- 1> application:start(test).
- test app start
- test sup start link
- test sup init
- ok
- 2> application:loaded_applications().
- [{kernel,"ERTS CXC 138 10","2.16.2"},
- {stdlib,"ERTS CXC 138 10","1.19.2"},
- {test,"Test application","1.0.0"}]
Erlang/OTP Application启动流程:
1、当erlang 执行application:start(test) 时,erlang会查找工作目录有没有 test.app 这个资源文件,没找到就报错,如果找到,就按照 test.app 这个文件的指示,启动 test 应用。
- %% 比较完整的资源文件:
- {application,test, % 名称
- [{description,"Test application"}, % 描述
- {vsn, "1.0.0"}, % 版本
- {id, Id}, % id 同 erl -id ID
- {modules, [test_app,test_sup]}, % 所有模块,systools用来生成script/tar文件
- {maxP, Num}, % 最大进程数
- {maxT, Time}, % 运行时间 单位毫秒
- {registered, [test_app]}, % 指定名称,systools用来解决名字冲突
- {included_applictions, []}, % 指定子app,加载但不启动
- {mod, {test_app,[]}}, % 启动模块,[]为参数
- {env, []}, % 配置env,可以使用application:get_env获取
- {applications,[kernel,stdlib]}]}. % 依赖项,启动app前,必须有启动的app
2、这里重点看 {mod, {test_app,[]}} 参数,意思是告诉 erlang 要调用应用模块(test_app)的start/2 函数。
- -module(test_app).
- start(_Type, StartArgs) ->
- io:format("test app start~n"),
- case test_sup:start_link(StartArgs) of
- {ok, Pid} ->
- {ok, Pid};
- Error ->
- Error
- end.
3、紧接着,到了监督者模块(test_sup),监督者模块启动了一个监督者进程,该进程会回调监督者模块的 init/1 函数,根据这个函数的返回值来启动子进程。
- %% 比较完整的监督者模块 init/1 函数,仅参考,下篇再介绍参数意义
- init([]) ->
- {ok,
- {{one_for_one, 1, 60}, % Strategy = {How, Max, Within}
- [{ test_handler_worker, % Id = internal id
- {test_server, start, []}, % StartFun = {M, F, A}
- permanent, % Restart = permanent | transient | temporary
- 2000, % Shutdown = brutal_kill | int() >= 0 | infinity
- worker, % Type = worker | supervisor
- [test_server] % Modules = [Module] | dynamic
- }]
- }
- }.