8  包含的应用程序

8  包含的应用程序

一个应用程序可以**包含**其他应用程序。一个**包含的应用程序**拥有自己的应用程序目录和 .app 文件,但它作为另一个应用程序的监控树的一部分启动。

一个应用程序只能被一个其他应用程序包含。

一个包含的应用程序可以包含其他应用程序。

没有被任何其他应用程序包含的应用程序称为**主应用程序**。

IMAGE MISSING

图 8.1:   主应用程序和包含的应用程序

应用程序控制器在加载主应用程序时自动加载所有包含的应用程序,但不会启动它们。相反,包含的应用程序的顶级监控器必须由包含应用程序中的监控器启动。

这意味着,在运行时,包含的应用程序实际上是主应用程序的一部分,包含的应用程序中的进程认为自己属于主应用程序。

要包含哪些应用程序由 .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"}]}
 ]}.

包含的应用程序的监控树作为包含应用程序的监控树的一部分启动。如果需要在包含应用程序和包含的应用程序中的进程之间进行同步,可以通过使用**启动阶段**来实现。

启动阶段由 .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}} 选项。此选项用于查找应用程序的回调模块 ModuleStartArgs 被忽略,因为 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