Elixir Application #

一、Application概述 #

1.1 什么是Application #

Application是Elixir/OTP组织代码和运行时的基本单元,包含:

  • 模块和代码
  • 配置
  • 启动和停止逻辑

1.2 Application结构 #

text
my_app/
├── lib/
│   ├── my_app.ex
│   └── my_app/
│       ├── application.ex
│       └── worker.ex
├── config/
│   ├── config.exs
│   ├── dev.exs
│   ├── prod.exs
│   └── runtime.exs
├── test/
├── mix.exs
└── README.md

二、定义Application #

2.1 Application模块 #

elixir
defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      MyApp.Worker
    ]

    Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
  end

  @impl true
  def stop(_state) do
    :ok
  end
end

2.2 mix.exs配置 #

elixir
defmodule MyApp.MixProject do
  use Mix.Project

  def project do
    [
      app: :my_app,
      version: "0.1.0",
      elixir: "~> 1.16",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  def application do
    [
      extra_applications: [:logger],
      mod: {MyApp.Application, []}
    ]
  end

  defp deps do
    []
  end
end

三、Application生命周期 #

3.1 启动 #

elixir
def start(_type, _args) do
  children = [
    MyApp.Repo,
    MyApp.Cache,
    MyApp.Worker
  ]

  opts = [strategy: :one_for_one, name: MyApp.Supervisor]
  Supervisor.start_link(children, opts)
end

3.2 停止 #

elixir
def stop(_state) do
  IO.puts("Application stopping")
  :ok
end

3.3 启动类型 #

  • :normal - 正常启动
  • :takeover - 从其他节点接管
  • :failover - 故障转移启动

3.4 prep_stop #

elixir
@impl true
def prep_stop(state) do
  IO.puts("Preparing to stop")
  state
end

四、Application环境 #

4.1 配置文件 #

elixir
# config/config.exs
import Config

config :my_app,
  name: "MyApp",
  version: "0.1.0"

config :my_app, MyApp.Repo,
  database: "my_app_dev",
  username: "postgres",
  password: "postgres",
  hostname: "localhost"

config :my_app, MyApp.Worker,
  batch_size: 100,
  timeout: 5000

4.2 环境特定配置 #

elixir
# config/dev.exs
import Config

config :my_app, MyApp.Repo,
  show_sensitive_data_on_connection_error: true

# config/prod.exs
import Config

config :my_app, MyApp.Repo,
  pool_size: 20

4.3 运行时配置 #

elixir
# config/runtime.exs
import Config

config :my_app, MyApp.Repo,
  database: System.get_env("DB_NAME") || "my_app",
  username: System.get_env("DB_USER") || "postgres",
  password: System.get_env("DB_PASS") || "postgres"

4.4 读取配置 #

elixir
iex(1)> Application.get_env(:my_app, :name)
"MyApp"

iex(2)> Application.get_env(:my_app, MyApp.Worker, [])
[batch_size: 100, timeout: 5000]

iex(3)> Application.fetch_env(:my_app, :name)
{:ok, "MyApp"}

iex(4)> Application.fetch_env!(:my_app, :name)
"MyApp"

4.5 更新配置 #

elixir
iex(1)> Application.put_env(:my_app, :name, "NewName")
:ok

五、Application回调 #

5.1 start_phase #

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

def start_phase(:init, _start_type, _phase_args) do
  IO.puts("Init phase")
  :ok
end

def start_phase(:migrate, _start_type, _phase_args) do
  IO.puts("Migrate phase")
  :ok
end

def start_phase(:ready, _start_type, _phase_args) do
  IO.puts("Ready phase")
  :ok
end

5.2 配置启动阶段 #

elixir
def application do
  [
    extra_applications: [:logger],
    mod: {MyApp.Application, []},
    start_phases: [
      init: [],
      migrate: [],
      ready: []
    ]
  ]
end

六、依赖Application #

6.1 extra_applications #

elixir
def application do
  [
    extra_applications: [:logger, :crypto, :ssl]
  ]
end

6.2 applications(已弃用) #

elixir
def application do
  [
    applications: [:logger, :crypto]
  ]
end

6.3 included_applications #

elixir
def application do
  [
    included_applications: [:my_internal_app]
  ]
end

七、Application管理 #

7.1 启动Application #

elixir
iex(1)> Application.ensure_all_started(:my_app)
{:ok, []}

iex(2)> Application.start(:my_app)
:ok

7.2 停止Application #

elixir
iex(1)> Application.stop(:my_app)
:ok

7.3 查看Application信息 #

elixir
iex(1)> Application.started_applications()
[{:my_app, 'My Application', '0.1.0'}, ...]

iex(2)> Application.info()

7.4 Application规范 #

elixir
iex(1)> Application.spec(:my_app)
[description: 'My Application', id: [], modules: [...], ...]

八、多Application项目 #

8.1 Umbrella项目 #

text
my_umbrella/
├── apps/
│   ├── app_one/
│   │   ├── lib/
│   │   ├── mix.exs
│   │   └── ...
│   └── app_two/
│       ├── lib/
│       ├── mix.exs
│       └── ...
├── config/
│   └── config.exs
└── mix.exs

8.2 创建Umbrella项目 #

bash
mix new my_umbrella --umbrella
cd my_umbrella/apps
mix new app_one
mix new app_two

8.3 Umbrella mix.exs #

elixir
defmodule MyUmbrella.MixProject do
  use Mix.Project

  def project do
    [
      apps_path: "apps",
      version: "0.1.0",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  defp deps do
    []
  end
end

九、最佳实践 #

9.1 Application模块组织 #

elixir
defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      MyApp.Repo,
      MyApp.Cache,
      MyApp.PubSub,
      MyApp.Scheduler,
      MyAppWeb.Endpoint
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end

  @impl true
  def stop(_state) do
    :ok
  end
end

9.2 配置组织 #

elixir
# config/config.exs
import Config

config :my_app,
  ecto_repos: [MyApp.Repo]

import_config "#{config_env()}.exs"

十、总结 #

本章学习了:

特性 用途
use Application 定义Application
start/2 启动回调
stop/1 停止回调
Application.get_env 读取配置
config/config.exs 配置文件

准备好学习Release了吗?让我们进入下一章。

最后更新:2026-03-27