在Elixir中动态加载/卸载模块,类似于插件系统

时间:2017-11-09 06:16:52

标签: elixir

我想创建类似插件系统的东西:一堆动态加载/卸载的模块,添加我插入/删除它们。

这样的事情:

# plugin1.eex
defmodule MyApp.Plugins.Plugin1 do

  def plugin_main_func(arg1, arg2) do
    # some stuff
  end
end

# plugin2.eex
defmodule MyApp.Plugins.Plugin2 do

  def plugin_main_func(arg1, arg2) do
    # some stuff 2
  end
end


# plugin3.eex
defmodule MyApp.Plugins.Plugin3 do

  def plugin_main_func(arg1, arg2) do
    # some stuff 3
  end
end

它们将具有相同的通用功能 - “plugin_main_func” - 每个插件的实现方式都不同。 在我的应用程序的某个地方,我会有这个:

plugins = load_plugins()
Enum.each plugins, &(&1.plugin_main_func(1, "fdafdsfds"))

然后我可以通过创建或删除适当的模块或文件来添加或删除插件。 没有必须在应用程序的某处硬编码/添加/删除他们的名称作为字符串列表以及

我怎么能做到这一点?

更新

鉴于插件必须存在于MyApp.Plugins并且具有函数plugin_main_func,我如何观察它们当前存在的插件列表?我只是想避免在某处硬编码他们的名字,加载或运行它们只有这两个条件足以找到所有的插件。

当我动态或半动态地找到所有这些内容时,我想以某种方式在每个插件中调用plugin_main_func。不知道插件的数量和它们的确切名称。怎么样?

我可以在编译之前加载它们,而不是在运行时加载它们。

2 个答案:

答案 0 :(得分:8)

回答标题中所述的问题:是的,可以在Elixir中动态加载/卸载模块。用例如编译代码Code.ensure_compiled/1并使用Erlang的code模块清除它:

:code.delete MyApp.Plugins.Plugin1
:code.purge MyApp.Plugins.Plugin1

回答整个问题:你做错了。 Elixir是一种编译语言,你正在滥用它。在运行时编译绝对不是Elixir的好处。

您只需要保留一个“已加载”插件列表,以伪造您尝试实现的行为。 load会将模块名称添加到列表中,unload会将其从列表中删除。就是这样。您不需要在运行时加载/卸载任何内容:它非常无效,危险且反惯用。如果您需要良好的运行时插件支持,请访问甚至

要在运行时获取已加载模块的列表,可以使用:

:application.get_key(:my_app, :modules)

您可以将插件限制在所需的命名空间(例如MyApp.Plugins),并按该名称过滤列表。

答案 1 :(得分:2)

@mudasobwa提供的答案非常棒。我所能做的就是给你一个提示,告诉你如何在运行时实现你想要的东西(顺便说一下 - 你在尝试使用"多态性"在Elixir中,很好)。

假设加载了这些模块,我不会处理编译器加载/删除它们。考虑使用存储状态的任何东西 - public slots:,GenServer,Agent等。

我会选择实现自己的GenServer,因为它可以灵活地自由地根据需要自定义它。想象一下:ets在您的GenServer上创建load_plugins()的情况,例如

call

您的GenServer以预定义的插件列表开始,您定义了API以在状态中添加/删除它们。绝对不需要在运行时加载/编译它们,即使它是可能的。

<强>更新

您始终可以使用def load_plugins do GenServer.call(MyServer, :load_plugins) end 检查模块是否已加载:

Code.ensure_loaded?
相关问题