8 包含的应用程序
8.1 简介
一个应用程序可以**包含**其他应用程序。一个**包含的应用程序**拥有自己的应用程序目录和 .app 文件,但它作为另一个应用程序的监控树的一部分启动。
一个应用程序只能被一个其他应用程序包含。
一个包含的应用程序可以包含其他应用程序。
没有被任何其他应用程序包含的应用程序称为**主应用程序**。
应用程序控制器在加载主应用程序时自动加载所有包含的应用程序,但不会启动它们。相反,包含的应用程序的顶级监控器必须由包含应用程序中的监控器启动。
这意味着,在运行时,包含的应用程序实际上是主应用程序的一部分,包含的应用程序中的进程认为自己属于主应用程序。
8.2 指定包含的应用程序
要包含哪些应用程序由 .app 文件中的 included_applications 键定义
{application, prim_app, [{description, "Tree application"}, {vsn, "1"}, {modules, [prim_app_cb, prim_app_sup, prim_app_server]}, {registered, [prim_app_server]}, {included_applications, [incl_app]}, {applications, [kernel, stdlib, sasl]}, {mod, {prim_app_cb,[]}}, {env, [{file, "/usr/local/log"}]} ]}.
8.3 启动期间同步进程
包含的应用程序的监控树作为包含应用程序的监控树的一部分启动。如果需要在包含应用程序和包含的应用程序中的进程之间进行同步,可以通过使用**启动阶段**来实现。
启动阶段由 .app 文件中的 start_phases 键定义,它是一个包含元组 {Phase,PhaseArgs} 的列表,其中 Phase 是一个原子,PhaseArgs 是一个项。
包含应用程序的 mod 键的值必须设置为 {application_starter,[Module,StartArgs]},其中 Module 通常是应用程序回调模块。 StartArgs 是提供给回调函数 Module:start/2 的参数。
{application, prim_app, [{description, "Tree application"}, {vsn, "1"}, {modules, [prim_app_cb, prim_app_sup, prim_app_server]}, {registered, [prim_app_server]}, {included_applications, [incl_app]}, {start_phases, [{init,[]}, {go,[]}]}, {applications, [kernel, stdlib, sasl]}, {mod, {application_starter,[prim_app_cb,[]]}}, {env, [{file, "/usr/local/log"}]} ]}. {application, incl_app, [{description, "Included application"}, {vsn, "1"}, {modules, [incl_app_cb, incl_app_sup, incl_app_server]}, {registered, []}, {start_phases, [{go,[]}]}, {applications, [kernel, stdlib, sasl]}, {mod, {incl_app_cb,[]}} ]}.
当启动具有包含应用程序的主应用程序时,主应用程序以通常的方式启动,即
- 应用程序控制器为应用程序创建一个应用程序主控器
- 应用程序主控器调用 Module:start(normal, StartArgs) 来启动顶级监控器。
然后,对于主应用程序和每个包含的应用程序,从上到下、从左到右的顺序,应用程序主控器为每个为主应用程序定义的阶段调用 Module:start_phase(Phase, Type, PhaseArgs)。如果包含的应用程序没有定义阶段,则不会为该阶段和应用程序调用该函数。
以下要求适用于包含应用程序的 .app 文件
- 必须包含 {mod, {Module,StartArgs}} 选项。此选项用于查找应用程序的回调模块 Module。 StartArgs 被忽略,因为 Module:start/2 仅针对主应用程序调用。
- 如果包含的应用程序本身包含包含的应用程序,则必须包含 {mod, {application_starter, [Module,StartArgs]}} 选项。
- 必须包含 {start_phases, [{Phase,PhaseArgs}]} 选项,并且指定的阶段集必须是为主应用程序指定的阶段集的子集。
当启动如上定义的 prim_app 时,应用程序控制器在 application:start(prim_app) 返回值之前调用以下回调函数
application:start(prim_app) => prim_app_cb:start(normal, []) => prim_app_cb:start_phase(init, normal, []) => prim_app_cb:start_phase(go, normal, []) => incl_app_cb:start_phase(go, normal, []) ok