当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Elixir Application用法及代码示例


Elixir语言中 Application 相关用法介绍如下。

用于处理应用程序和定义应用程序回调的模块。

应用程序是在 Erlang/OTP 中打包软件的惯用方式。为了理解这个想法,它们类似于其他编程语言中常见的"library" 概念,但具有一些额外的特征。

应用程序是实现某些特定函数的组件,具有标准化的目录结构、配置和生命周期。应用程序是 loadedstartedstopped 。每个应用程序也有自己的环境,它为配置每个应用程序提供了统一的 API。

开发人员通常与应用程序环境及其回调模块进行交互。因此,这些将是我们在进入有关应用程序资源文件和life-cycle 的详细信息之前首先介绍的主题。

应用环境

每个应用程序都有自己的环境。环境是将原子映射到术语的关键字列表。请注意,此环境与操作系统环境无关。

默认情况下,应用程序的环境是一个空列表。在 Mix 项目的 mix.exs 文件中,您可以在 application/0 中设置 :env 键:

def application do
  [env: [db_host: "localhost"]]
end

现在,在您的应用程序中,您可以使用 fetch_env!/2 和朋友等函数来读取此环境:

defmodule MyApp.DBClient do
  def start_link() do
    SomeLib.DBClient.start_link(host: db_host())
  end

  defp db_host do
    Application.fetch_env!(:my_app, :db_host)
  end
end

在 Mix 项目中,可以通过 config/config.exsconfig/runtime.exs 文件覆盖应用程序的环境及其依赖项。前者在您的代码编译之前在build-time 加载,而后者在运行时加载,就在您的应用程序启动之前。例如,使用您的应用程序的人可以覆盖其:db_host 环境变量,如下所示:

import Config
config :my_app, :db_host, "db.local"

有关详细信息,请参阅 Mix 模块中的"Configuration" 部分。

您还可以使用 put_env/3 delete_env/2 等函数动态更改应用程序环境。但是,根据经验,每个应用程序都负责自己的环境。请不要使用本模块中的函数直接访问或修改其他应用程序的环境。

编译时环境

在前面的示例中,我们在运行时读取应用程序环境:

defmodule MyApp.DBClient do
  def start_link() do
    SomeLib.DBClient.start_link(host: db_host())
  end

  defp db_host do
    Application.fetch_env!(:my_app, :db_host)
  end
end

换言之,应用程序:my_app 的环境 key :db_host 仅在MyApp.DBClient 有效启动时才会被读取。虽然在运行时读取应用程序环境是首选方法,但在极少数情况下,您可能希望使用应用程序环境来配置某个项目的编译。这通常通过在函数外部调用 get_env/3 来完成:

defmodule MyApp.DBClient do
  @db_host Application.get_env(:my_app, :db_host, "db.local")

  def start_link() do
    SomeLib.DBClient.start_link(host: @db_host)
  end
end

这种方法有一个很大的局限性:如果你在代码编译后改变了应用环境的值,运行时使用的值是不会改变的!例如,如果您的 config/runtime.exs 具有:

config :my_app, :db_host, "db.production"

该值将不起作用,因为编译代码以连接到"db.local",这在生产环境中很可能不可用。

由于这些原因,在运行时读取应用程序环境应该是首选。但是,如果您在编译时确实需要阅读应用程序环境,我们建议您改用 compile_env/3

require Application
@db_host Application.compile_env(:my_app, :db_host, "db.local")

通过使用 compile_env/3 ,诸如 Mix 之类的工具将存储编译期间使用的值,并在系统启动时将编译值与运行时值进行比较,如果它们不同,则会引发错误。

应用回调模块

可以加载、启动和停止应用程序。通常,像 Mix 这样的构建工具会为您启动应用程序及其所有依赖项,但您也可以通过调用手动完成:

{:ok, _} = Application.ensure_all_started(:some_app)

当应用程序启动时,开发人员可以配置一个执行自定义代码的回调模块。开发者使用这个回调来启动应用监督树。

这样做的第一步是将:mod 键添加到mix.exs 文件中的application/0 定义中。它需要一个元组,带有应用程序回调模块和开始参数(通常是一个空列表):

def application do
  [mod: {MyApp, []}]
end

赋予:modMyApp 模块需要实现 Application 行为。这可以通过将use Application 放入该模块并实现 start/2 回调来完成,例如:

defmodule MyApp do
  use Application

  def start(_type, _args) do
    children = []
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end

start/2 回调必须生成和链接一个监督者并返回 {:ok, pid}{:ok, pid, state} ,其中 pid 是监督者的 PID,而 state 是一个可选的应用程序状态。 args 是赋予:mod 选项的元组的第二个元素。

传递给 start/2 type 参数通常是:normal,除非在配置了应用程序接管和故障转移的分布式设置中。分布式应用程序超出了本文档的范围。

当应用程序关闭时,它的 stop/1 回调会在运行时停止监督树后调用。此回调允许应用程序进行任何最终清理。参数是 start/2 返回的状态,如果是,或者 [] 否则。 stop/1 的返回值被忽略。

通过使用 Application ,模块会获得 stop/1 的默认实现,该实现忽略其参数并返回 :ok ,但它可以被覆盖。

应用程序回调模块也可以实现可选的回调 prep_stop/1 。如果存在,则在终止监督树之前调用 prep_stop/1 。它的参数是 start/2 返回的状态,如果是的话,或者 [] 否则,它的返回值被传递给 stop/1

应用程序资源文件

在上面的部分中,我们在mix.exs 文件的application/0 部分中配置了一个应用程序。最终,Mix 将使用此配置创建一个 application resource file ,这是一个名为 APP_NAME.app 的文件。例如,OTP 应用程序 ex_unit 的应用程序资源文件称为 ex_unit.app

您可以在 Mix.Tasks.Compile.App 的文档中了解有关生成应用程序资源文件的更多信息,也可以通过运行 mix help compile.app 来获得。

应用程序生命周期

加载应用程序

应用程序是 loaded ,这意味着运行时会查找并处理它们的资源文件:

Application.load(:ex_unit)
#=> :ok

加载应用程序时,其资源文件中指定的环境将与配置文件中的任何覆盖合并。

加载应用程序 does not 加载其模块。

在实践中,您很少手动加载应用程序,因为这是启动过程的一部分,接下来会解释。

启动应用程序

应用程序也是 started

Application.start(:ex_unit)
#=> :ok

编译应用程序后,运行系统就是启动当前应用程序及其依赖项的问题。与其他语言不同,Elixir 没有负责启动系统的main 过程。相反,您启动一个或多个应用程序,每个应用程序都有自己的初始化和终止逻辑。

启动应用程序时,如果尚未完成,则会自动调用 Application.load/1 。然后,它检查资源文件的applications 键中列出的依赖项是否已经启动。至少有一个依赖项未启动是一种错误情况。 ensure_all_started/1 之类的函数负责为您启动应用程序及其所有依赖项。

如果应用程序没有配置回调模块,则在此时完成启动。否则,将调用其 start/2 回调。此函数返回的顶级主管的 PID 由运行时存储以供以后使用,如果有的话,也会保存返回的应用程序状态。

停止应用程序

最后,启动的应用程序是 stopped

Application.stop(:ex_unit)
#=> :ok

定义了在没有回调模块的情况下停止应用程序,但除了一些系统跟踪之外,它实际上是一个no-op。

使用回调模块停止应用程序分为三个步骤:

  1. 如果存在,调用可选的回调 prep_stop/1
  2. 终止顶级主管。
  3. 调用所需的回调 stop/1

传递给回调的参数与 start/2 可选返回的状态相关,并在上面有关回调模块的部分中记录。

重要的是要强调步骤 2 是一个阻塞步骤。主管的终止触发子终止的递归链,因此有序地关闭所有后代进程。 stop/1 回调仅在整个监督树终止后调用。

可以通过调用 System.stop/1 来彻底关闭实时系统。它将以与启动相反的顺序关闭每个应用程序。

默认情况下,来自操作系统的 SIGTERM 将自动转换为 System.stop/0 。您还可以通过 :os.set_signal/2 函数对操作系统信号进行更明确的控制。

工装

Mix 构建工具可自动执行大多数应用程序管理任务。例如, mix test 在测试运行之前自动启动您的应用程序依赖项和应用程序本身。 mix run --no-halt 引导您当前的项目,并可用于启动长时间运行的系统。请参阅 mix help run

开发人员还可以使用 mix release 来构建版本。发行版能够将您的所有源代码以及 Erlang VM 打包到一个目录中。发布还使您可以明确控制每个应用程序的启动方式和顺序。它们还为启动和停止系统、调试、日志记录以及系统监视提供了更简化的机制。

最后,Elixir 提供了诸如 escripts 和 archives 之类的工具,它们是打包应用程序的不同机制。这些通常在必须在开发人员之间共享工具而不是作为部署选项时使用。有关详细信息,请参阅 mix help archive.build mix help escript.build

更多信息

有关应用程序的更多详细信息,请查看文档:application Erlang 模块, 和应用的部分OTP 设计原则用户指南.

相关用法


注:本文由纯净天空筛选整理自elixir-lang.org大神的英文原创作品 Application。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。