首先,类型的语法,源代码中使用的-callback,现在的新的语法应该已经和-spec一样了,即前者的功能后者也可以实现了,因此在erlang编程设计中也是使用-spec。同时,这里的对于函数的测试,一般都是返回一个元组{ok, ...}。
这里首先调用gen:start,后者通过start函数来调用do_spawn函数,do_spawn则调用proc_lib的start或者start_link函数,这里第二个参数是init_it,因此可以知道,调用gen_server的start或者start_link函数之后,proc_lib的start或者start_link函数最终将调用erlang的spawn_monitor或者spawn_link函数。
start_link(Mod,Args,Options)->
gen:start(?MODULE,link,Mod,Args,Options).
do_spawn(GenMod,link,Mod,Args,Options)->
Time=timeout(Options),
proc_lib:start_link(?MODULE,init_it,
[GenMod,self(),self(),Mod,Args,Options],
Time,
spawn_opts(Options));
start_link(M,F,A)whenis_atom(M),is_atom(F),is_list(A)->
start_link(M,F,A,infinity).
反正一路调用下来,终于是进入init_it函数执行。这里case一行调用回调模块中的init函数。之后根据init的返回值来选择不同的loop循环来执行,或者停止等其他动作。
init_it(Starter,Parent,Name0,Mod,Args,Options)->
Name=gen:name(Name0),
Debug=gen:debug_options(Name,Options),
HibernateAfterTimeout=gen:hibernate_after(Options),
%%下面调用回调模块的init函数
caseinit_it(Mod,Args)of%根据init函数返回值选择分支执行
{ ok, { ok,State}} ->
proc_lib:init_ack(Starter, { ok,self()}),%告诉parent进程已经初始化了,初始化开始或者失败
loop(Parent,Name,State,Mod,infinity,HibernateAfterTimeout,Debug);%进入loop循环,infinity
{ ok, { ok,State,Timeout}} ->% infinity表示gen_server进程一直运行下去
proc_lib:init_ack(