以前研读过一次Erlang OTP框架,但总觉得理解还不够,没有亲手实现一个应用。纸上得来终觉浅,绝知此事须躬行。:)
近日恰好有时间,又把Erlang OTP框架拿来研读,并尝试完成了一个简单的用OTP实现的应用。本应用同时实现了一个事件管理器及相关测试代码。
应用实例中实现的行为模式包括application、supervisor、gen_server、gen_event,实现的简单功能是定制事件管理器来实现事件日志,可以添加和删除事件管理器,并使用自定义的事件管理器输出事件日志,使用应用来启动监督进程,利用监督进程管理普通服务器和事件管理器的进程。
应用实例的主要模块包括:event_app(实现application)、root_sup(实现supervisor)、myserv(实现gen_server)、event_mod(实现gen_event)。应用的目录结构也采取最简单的形式,即项目主目录下仅有两个子目录:ebin 和 src。
其基本代码如下:
%filename event_app.app
%应用资源文件
{application, event_app,
[{description,"a simple logger."},
{vsn,"1.0"},
{modules,[event_mod,root_sup,event_app,myserv]},
{registered,[event_mod,root_sup,myserv]},
{applications,[kernel,stdlib]},
{mod,{event_app,[]}}]}. %%指明应用启动模块
%filename event_app.erl
-module (event_app).
-behaviour (application). %%实现应用行为
-compile(export_all).
start(_Type,_StartArgs) ->
case root_sup:start_link() of
{ok,Pid} -> {ok,Pid};
Other ->
{error,Other}
end.
stop(_State) -> ok.
%filename root_sup
-module (root_sup).
-behaviour (supervisor). %%实现监督者行为
-compile(export_all).
start_link() ->
supervisor:start_link({local,?MODULE},?MODULE,[]).
init([]) ->
Event = {event_mod,{event_mod,start_link,[]},
permanent,2000,worker,[event_mod]},
Myserv = {myserv,{myserv,start_link,[]},
permanent,2000,worker,[myserv]},
Children = [Event,Myserv],
RestartStrategy = {one_for_one,0,1},
{ok,{RestartStrategy,Children}}. %%返回监控进程规范和子进程规范列表
%filename myserv.erl
-module (myserv).
-behaviour (gen_server).
-compile(export_all).
start_link() ->
gen_server:start_link({local,?MODULE},?MODULE,[],[]).
init([]) ->{ok,[]}.
add_hdl() -> %%添加自定义事件处理器(用户API)
gen_server:cast(?MODULE,addhdl).
del_hdl() -> %%删除自定义事件处理器(用户API)
gen_server:cast(?MODULE,delhdl).
log_test() -> %%引发日志事件测试
event_mod:log_test(). %%通过调用委托给event_mod模块
handle_cast(addhdl,State) ->
event_mod:add_handler(), %%通过调用委托给event_mod模块
{noreply,State};
handle_cast(delhdl,State) ->
event_mod:del_handler(), %%通过调用委托给event_mod模块
{noreply,State}.
%%其它消息不作处理
handle_call(_,_,State) -> {reply,{ok,ok},State}.
handle_info(_,State) -> {noreply,State}.
code_change(_OldVsn,State,_Extra) -> {ok,State}.
terminate(_,_) -> ok.
%filename event_mod.erl
-module (event_mod).
-compile(export_all).
-behaviour (gen_event). %%实现事件管理器行为
start_link() ->
gen_event:start_link({local,?MODULE}).
init([]) -> {ok,[]}.
add_handler() -> %%添加事件管理器
gen_event:add_handler(?MODULE,?MODULE,[]).
delete_handler() -> %%删除事件管理器
gen_event:delete_handler(?MODULE,?MODULE,[]).
log_test() -> %%引发日志事件测试函数
gen_event:notify(?MODULE,test). %%引发日志事件
handle_event(test,State) -> %%引发日志事件的处理函数
error_logger:info_msg("Test send up.~n"),
{ok,File} = file:open("aqw.txt",write), %%可将相关日志信息写入指定文件,实际程序中文件名不会硬编码
io:format(File,"aqwkdkkdkd~n",[]),
file:close(File),
{ok,State};
handle_event(_Msg,State) ->
{ok,State}.