application_controller
是系统最早启动的process
之一,也是非分布式application
的管理所在
1. application_controller
是什么?
The application_controller controls local applications only.
A local application can be loaded/started/stopped/unloaded and changed.
The control of distributed applications is taken care of by another process (default is dist_ac).
简单的说这个process(application_controller)
就是控制非分布式application
的真正所在
2.application_controller
什么时候启动?
2.1 otp-20中 application_controller
启动顺序
$ erl -init_debug
{progress,preloaded}
{progress,kernel_load_completed}
{progress,modules_loaded}
{start,heart}
{start,error_logger}
{start,application_controller}
{progress,init_kernel_started}
...
是继heart,error_logger
之后启动,而且在kernel
启动之前,因为kernel
也是一个application
2.2 otp-21中 application_controller
启动顺序
$ erl -init_debug
{progress,preloaded}
{progress,kernel_load_completed}
{progress,modules_loaded}
{start,heart}
{start,logger}
{start,application_controller}
{progress,init_kernel_started}
...
由于在otp-21中,将error_logger
改为logger
不管怎么说,application_controller
启动的顺序都在kernel
之前,级别和init
相当
3. application 其实是 application_controller 的代理(proxy)
application
的一般操作,实际上都是调用application_controller
,上代码
% start/2
start(Application, RestartType) ->
case load(Application) of
ok ->
Name = get_appl_name(Application),
application_controller:start_application(Name, RestartType);
{error, {already_loaded, Name}} ->
application_controller:start_application(Name, RestartType);
Error ->
Error
end.
% start_boot/2
start_boot(Application, RestartType) ->
application_controller:start_boot_application(Application, RestartType).
% stop/1
stop(Application) ->
application_controller:stop_application(Application).
% which_applications/0
which_applications() ->
application_controller:which_applications().
% loaded_applications
loaded_applications() ->
application_controller:loaded_applications().
% set_env/3
set_env(Application, Key, Val) ->
application_controller:set_env(Application, Key, Val).
% get_env/2
get_env(Application, Key) ->
application_controller:get_env(Application, Key).
4.详细的分析每个行为
4.1 数据结构appl_data
-record(appl_data, {name, regs = [], phases, mod, mods = [],
inc_apps, maxP = infinity, maxT = infinity}).
4.2 载入application
% application_controller.erl
handle_call({load_application, Application}, From, S) ->
case catch do_load_application(Application, S) of
{ok, NewS} ->
AppName = get_appl_name(Application),
% 如果是分布式 app,就给dist_ac发送一条消息
case cntrl(AppName, S, {ac_load_application_req, AppName}) of
true ->
% 如果App是一个分布式Application,那么控制权交给 dist_ac
{noreply, S#state{loading = [{AppName, From} | S#state.loading]}};
false ->
{reply, ok, NewS}
end;
{error, _} = Error ->
{reply, Error, S};
{'EXIT', R} ->
{reply, {error, R}, S}
end;
简单的说就是从${App}.app
构建#appl_data{}
如果这个 app是分布式的,那么就给dist_ac
发送消息{ac_load_application_req,App}
等待dist_ac
返回数据
4.2 启动 application
% application_controller.erl
handle_call({start_application, AppName, RestartType}, From, S) ->
#state{running = Running, starting = Starting, start_p_false = SPF,
started = Started, start_req = Start_req} = S,
case lists:keyfind(AppName, 1, Start_req) of
false ->
case catch check_start_cond(AppName, RestartType, Started, Running) of
{ok, Appl} ->
Cntrl = cntrl(AppName, S, {ac_start_application_req, AppName}),
Perm = application:get_env(kernel, permissions),
case {Cntrl, Perm} of
{true, _} ->
% 控制权交给 dist_ac
{noreply, S#state{...}};
{false, undefined} ->
% 非分布式应用,就直接启动了
spawn_starter(From, Appl, S, normal),
{noreply, S#state{...}};
{false, {ok, Perms}} ->
case lists:member({AppName, false}, Perms) of
false ->
% 在权限允许分为内,也直接启动了
spawn_starter(From, Appl, S, normal),
{noreply, S#state{...};
true ->
% 不在权限允许内,不能启动,默认返回ok
SS = S#state{...},
{reply, ok, SS}
end
end;
{error, _R} = Error ->
{reply, Error, S}
end;
{AppName, _FromX} ->
% 已经有一个请求了,同一个app不能启动2次
SS = S#state{...},
{noreply, SS}
end;
简单的说,分布式application
控制权交给dist_ac
,非分布式application
,就直接启动了
还有一点application_controller
和application
并不是直接link
在一起的,就拿kernel
举例,他们之间还有两层代理.拓扑图如下
|application_controller|
|(link)
|application_master:main_loop/2|% 控制该 application最多运行时长(maxT)
|(link)
|application_master:loop_it/4|% 控制application的生命周期以及各种回调 start/2,stop/2,pre_stop/1
|(link)
|kernel_sup|
4.3 start_boot_application
与 start_application
不同的是,这个调用来自生成的boot
文件,逻辑与start_applicaton
一样
4.4 停止application
% application_controller.erl
handle_call({stop_application, AppName}, _From, S) ->
#state{running = Running, started = Started} = S,
case lists:keyfind(AppName, 1, Running) of
{_AppName, Id} ->
{_AppName2, Type} = lists:keyfind(AppName, 1, Started),
% 自己管理的才停止
stop_appl(AppName, Id, Type),
NRunning = keydelete(AppName, 1, Running),
NStarted = keydelete(AppName, 1, Started),
cntrl(AppName, S, {ac_application_stopped, AppName}),
{reply, ok, S#state{running = NRunning, started = NStarted}};
false ->
case lists:keymember(AppName, 1, Started) of
true ->
NStarted = keydelete(AppName, 1, Started),
% 不是自己管理的还是得交给 dist_ac
cntrl(AppName, S, {ac_application_stopped, AppName}),
{reply, ok, S#state{started = NStarted}};
false ->
{reply, {error, {not_started, AppName}}, S}
end
end;
与之前start_application
相同,只停止自己管理的app
,分布式app
还是交给dist_ac
5.总结
-
application_controller
是最早启动的线程之一 -
application_controller
才是其实处理启动app
,停止app
的process
-
application_controller
在遇到分布式app
的时候会将控制权交给dist_ac