當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。