一个完整的OTP应用简例

    以前研读过一次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}.

运行测试结果如下图:


猜你喜欢

转载自blog.csdn.net/cloveses/article/details/78874403