O

OTP 应用程序的结构

2025-06-04

OTP 应用程序的结构

OTP是一个提供标准来帮助构建 Erlang 应用程序的框架,它使用应用程序将代码打包成单元或组件。此约定有助于将代码组织成逻辑模块组,并提供一种启动和停止应用程序监控器的方法。您的 Phoenix 项目是一个应用程序,但 Phoenix 框架和 Ecto 也是应用程序。

应用程序是一个可以自行编译的组件。它可以依赖于其他应用程序,并且可以采用自己的配置。与其他语言不同,此约定提供了一种标准化的方式来指定虚拟机应如何与其交互。

除了包含虚拟机代码的编译.beam文件之外,已编译的应用程序还包含一个应用程序规范 .app文件(用于告诉虚拟机如何处理应用程序)和一个可选的应用程序回调模块(用于启动、运行和停止应用程序)。

应用程序回调模块

对于带有监管器的应用程序,应用程序回调模块定义了启动和停止应用程序的函数。不带有监管器的应用程序(通常是一些库,其中包含一些无需内部状态即可调用的函数)则省略了回调模块,因为应用程序无需启动。

在 Elixir 中,应用程序回调模块使用行为。该Application行为实现了start/2stop/1回调。前者启动应用程序的主监督器,后者是一个可选回调,用于在监督器停止后进行清理。

mix new当使用该标志生成新项目时,Elixir 的任务会自动创建应用程序回调模块--sup

$ mix new --sup elixir_app
Enter fullscreen mode Exit fullscreen mode

生成的项目包含一个应用程序回调模块lib/elixir_app/application.ex

defmodule ElixirApp.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      # Starts a worker by calling: ElixirApp.Worker.start_link(arg)
      # {ElixirApp.Worker, arg},
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: ElixirApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
Enter fullscreen mode Exit fullscreen mode

使用时,该Application模块会添加函数的存根stop/1,该存根返回一个 ok 元组。生成的start/2函数会启动应用程序的主监控器。

应用程序规范

运行mix compile.app将应用程序的规范放在.app目录中的文件中ebin,这是使用 编译应用程序时采取的步骤之一mix compile

该规范包含定义应用程序的 Erlang 术语。它列出了应用程序中定义的模块、版本号以及应用程序所依赖的其他应用程序列表。它还指定了用作启动应用程序的回调的模块。

规范文件基于应用程序mix.exs文件中的设置。为了能够生成规范,每个应用程序必须在其项目函数中定义名称和版本号。

defmodule ElixirApp.MixProject do
  use Mix.Project

  def project do
    [
      app: :elixir_app,
      version: "0.1.0"
    ]
  end
end
Enter fullscreen mode Exit fullscreen mode

下面是一个最小示例mix.exs文件,其中仅列出项目名称和版本号,并生成一个列出 Elixir 默认应用程序并指定应用程序中的模块的规范。

{application,elixir_app,
             [{applications,[kernel,stdlib,elixir]},
              {description,"elixir_app"},
              {modules,['Elixir.ElixirApp','Elixir.ElixirApp.Application']},
              {registered,[]},
              {vsn,"0.1.0"}]}.
Enter fullscreen mode Exit fullscreen mode

指定和配置应用程序回调模块

除了应用程序的名称和版本号之外,mix.exs使用该--sup选项生成的文件还具有带键application的功能mod

defmodule ElixirApp.MixProject do
  # ...

  def application do
    [
      mod: {ElixirApp.Application, []}
    ]
  end
end
Enter fullscreen mode Exit fullscreen mode

生成规范时,它包含回调模块。此键指向应用程序的回调模块,因此虚拟机知道使用哪个模块来启动应用程序。

{application,elixir_app,
             [{applications,[kernel,stdlib,elixir,logger]},
              {description,"elixir_app"},
              {modules,['Elixir.ElixirApp','Elixir.ElixirApp.Application']},
              {registered,[]},
              {vsn,"0.1.0"},
              {mod,{'Elixir.ElixirApp.Application',[]}}]}.
Enter fullscreen mode Exit fullscreen mode

提示:-tuple 中的列表:mod用于将配置选项传递给应用程序。传入的任何内容最终都会作为回调模块start/2函数的参数。

:applications:extra_applications

applications规范中的键列出了你的应用所依赖的所有应用程序。默认情况下mix compile.app包括kernel stdlibelixir

defmodule ElixirApp.MixProject do
  use Mix.Project

  def project do
    [
      app: :elixir_app,
      version: "0.1.0",
      deps: [{:appsignal, "~> 1.0.0"}]
    ]
  end
end
Enter fullscreen mode Exit fullscreen mode

依赖项会自动添加到applications列表中,并且如果它们具有应用程序模块,则会在应用程序启动之前自动启动。

{application,elixir_app,
             [{applications,[kernel,stdlib,elixir,appsignal]},
              {description,"elixir_app"},
              {modules,['Elixir.ElixirApp','Elixir.ElixirApp.Application']},
              {registered,[]},
              {vsn,"0.1.0"}]}.
Enter fullscreen mode Exit fullscreen mode

要添加更多类似 Elixir 的应用程序logger,您可以将它们添加到:extra_applications密钥中,然后它们将被添加到现有列表中。

defmodule ElixirApp.MixProject do

  # ...

  def application do
    [
      extra_applications: [:logger],
      mod: {ElixirApp.Application, []}
    ]
  end
end
Enter fullscreen mode Exit fullscreen mode

:applications键用于明确指定要包含在规范中的应用程序。使用时,只会添加列出的应用程序和默认应用程序。任何其他依赖项都不会自动包含。

应用程序一路下降

每个独立的库以及你的应用程序本身都是一个应用程序。有些应用程序有一个监督树,需要它们有一个回调模块来负责启动和停止整个应用程序。

你的应用程序可以依赖于其他应用程序,每个应用程序都可以拥有自己的监督树和回调模块。无论其中包含什么,它始终会在应用程序规范文件中指定。你可以把它想象成 Elixir 的配方。😉

以上就是我们对 Elixir 中 OTP 应用的概述。我们尝试展现了 OTP 约定之一的魅力。这也是我们喜爱 Elixir 的众多原因之一。如果您也喜欢,请在评论区告诉我们您希望我们写什么,或者订阅Elixir Alchemy 的新闻简报

文章来源:https://dev.to/appsignal/how-otp-applications-are-structed-59e4
PREV
宣布发布 Appwrite 0.7 - 开源 Firebase 替代方案
NEXT
Ruby 中的闭包:Blocks、Procs 和 Lambdas