这可以通过向主管争论来解决。例如,Ecto 的后端主管采用一个名为adapter
指定应使用哪种类型的数据库:
# https://github.com/elixir-lang/ecto/blob/364d34bb135e2256fd48327464ada7f7fa2976f9/lib/ecto/repo/backend.ex#L13-L16
def start_link(repo, adapter) do
# Start Ecto, depending on the supplied <repo> and <adapter>
end
您可以在您的应用程序中执行相同的操作,可能是一个参数start_link
就足够了——我们就这么称呼它吧backend
# my_app/lib/my_app/supervisor.ex
defmodule MyApp.Supervisor do
def start_link(backend) do
# use <backend> as you need to in here,
# it will contain the module that is
# specified in the configuration file.
end
end
现在,您当然可以在启动应用程序时根据配置文件动态设置该参数:
# my_app/lib/my_app.ex
defmodule MyApp do
use Application
def start(_type, _args) do
MyApp.Supervisor.start_link(backend)
end
# get backend from configuration
def backend do
# ???
end
end
现在,唯一缺少的是如何从配置文件获取后端。这个问题没有单一的答案,因为有多种方法可以做到这一点。
混合配置
您可以简单地使用现有的 Mix 配置,但它的缺点是每次配置更改时都需要重新编译应用程序:
# my_app/config/config.exs
use Mix.Config
config :my_app, backend: MyApp.SpecificBackend
然后调整您的应用程序以读取指定的后端:
# my_app/lib/my_app.ex
defmodule MyApp do
use Application
def start(_type, _args) do
# same as above ...
end
def backend do
Application.get_env(:my_app, :backend)
end
end
滚动你自己的
您还可以实现自己的配置文件。我不会在这里详细讨论,但这是一个粗略的想法:
- 将配置文件保存在某处
- 在 Elixir 中阅读并解析它
- 将字符串转换为模块名称
String.to_existing_atom("Elixir.#{module_name}")
- 如果原子(即模块名称)不存在,这将引发错误
- 在你的
def backend
功能
使用现有的运行时配置库
基本上是先前解决方案的美化版本。谷歌搜索了一下我发现了一个名为Conform https://github.com/bitwalker/conform。它看起来很有趣,但我不能做出任何承诺,因为我自己从未使用过它。