http://hje.iteye.com/blog/1211734html
应用的概念¶
当咱们写了实现特定功能的代码以后,咱们可能想将代码转成一个 应用 (application),这是能够做为一个单元启动和中止的组建,同时它也能够在其余系统中被重用。
咱们要建立一个 应用回调模块 ,其中描述了该应用应该如何被启动和中止。
而后,须要一个应用规格,它被放在一个 应用资源文件 。咱们还指定该应用由哪些模块组成,以及各个回掉模块的名字。
若是咱们使用 systools ——Erlang/OTP用于打包的代码(参见 发布 ),每一个应用的代码均可以按照预约的 目录结构 放在单独的目录中。
应用回调模块¶
如何启动和中止应用的代码,即监督树,由如下两个回掉函数来描述:
start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State}
stop(State)
当要经过启动顶层督程来建立监督树的时候,会调用 start 。它要返回顶层督程的pid和一个选项值 State ,默认为 []。这个值会原样传递给 stop 。
StartType 一般是原子 normal 。只有在接管或故障转移中才会有其余值,参见 分布式应用 。 StartArgs 由 应用资源文件 中的键 mod 来定义。
在应用被中止以后会调用 stop/1 来进行必须的清除工做。注意应用实际的中止过程,也就是监督树的关闭,是按照 启动和中止应用 中所描述的方式自动处理的。
如下是一个例子,未来自 督程 一章中的督程打包为一个应用回调模块:
-module(ch_app).
-behaviour(application).
-export([start/2, stop/1]).
start(_Type, _Args) ->
ch_sup:start_link().
stop(_State) ->
ok.
一个库应用——不能被启动或者中止——则无须任何应用回调模块。
应用资源文件¶
咱们经过建立一个放在应用资源文件——简称 .app 文件——中的应用规格来定义一个应用:
{application, Application, [Opt1,...,OptN]}.
Application 是一个表明应用的名称的原子。文件必须被命名成 Application.app 。
每个 Opt 都是一个定义了应用某种特性的元组 {Key, Value} 。全部的键都是可选。忽略的键会使用默认的值。
例如,用于库应用 libapp 的最小化的 .app 文件的内容为:
{application, libapp, []}.
对于像 ch_app 这样的监督树应用的最小化 .app 文件的内容为:
{application, ch_app,
[{mod, {ch_app,[]}}]}.
键 mod 定义了回调模块以及应用的启动参数,在这个例子中相应是 ch_app 和 []。这表示应用启动的时候会调用:
ch_app:start(normal, [])
而当应用被中止的时候会调用:
ch_app:stop([])
当使用 systools 时,Erlang/OTP工具的打包代码(参见 发布 ),键 description、vsn、modules、registered 和 applications 则应该指定为:
{application, ch_app,
[{description, "Channel allocator"},
{vsn, "1"},
{modules, [ch_app, ch_sup, ch3]},
{registered, [ch3]},
{applications, [kernel, stdlib, sasl]},
{mod, {ch_app,[]}}
]}.
description
简短描述,字符串。默认为 “”。
vsn
版本号,字符串。默认为”“。
modules
由该应用引入的全部模块。当生成启动脚本和tar文件时, systools 将用到这个列表。一个模块必须被定义于且仅于一个应用。默认为[]。
registered
应用中全部注册进程的名称。 systools 使用这个列表来探测在应用之间是否有名称冲突。默认为 []。
applications
全部在此应用以前必须启动的应用。 systools 使用该列表来生成正确的启动脚本。默认为 [],可是注意任何应用都要至少依赖于 kernel 和 stdlib 。
应用资源文件的语法和内容在 app(4) 中有详细的描述。
目录结构¶
当使用 systools 对代码进行打包的时候,每一个应用的代码都放在单独的目录中 lib/Application-Vsn ,其中 Vsn 是版本号。
即使没有用到 systools ,最好也要了解它,由于Erlang/OTP其自身是按照OTP原则进行打包的因此才有了这个目录结构。若是存在一个应用的多个版本,那么代码服务器(见 code(3) )会自动使用来自目录中版本号最高的代码。
应用目录结构固然也能够用于开发环境。版本号是能够忽略的。
应用目录有如下子目录:
•src
•ebin
•priv
•include
src
包含Erlang源代码
ebin
包含Erlang目标代码—— beam 文件。 .app 文件也放在这里。
priv
用于应用专属文件。例如,C执行程序就放在这里。应该使用函数 code:priv_dir/1 来访问这个目录。
include
用于包含文件。
应用控制器¶
当启动了Erlang运行时系统,做为Kernel应用的一些进程会被启动。其中一个进程是应用控制器进程,注册为 application_controller 。
全部对应用的操做都由应用控制器来协调。它经过模块 application 里的函数来暴露接口, 请参考 application(3) 。尤为要了解,应用能够被加载、卸载、启动和中止。
加载和卸载应用¶
在能启动一个应用以前,首先它必须被加载。应用控制器会读取在 .app 中的信息并存起来。
1> application:load(ch_app).
ok
2> application:loaded_applications().
[{kernel,"ERTS CXC 138 10","2.8.1.3"},
{stdlib,"ERTS CXC 138 10","1.11.4.3"},
{ch_app,"Channel allocator","1"}]被中止的或者从未启动过的应用,能够被卸载。该应用相关的信息会从应用控制器的内部数据库中删除。
3> application:unload(ch_app).
ok
4> application:loaded_applications().
[{kernel,"ERTS CXC 138 10","2.8.1.3"},
{stdlib,"ERTS CXC 138 10","1.11.4.3"}]Note:
加载/卸载应用并不会加载/卸载该应用所使用的代码。代码加载是按照通常的方式进行的。
启动和中止应用¶
启动应用要调用:
5> application:start(ch_app).
ok
6> application:which_applications().
[{kernel,"ERTS CXC 138 10","2.8.1.3"},
{stdlib,"ERTS CXC 138 10","1.11.4.3"},
{ch_app,"Channel allocator","1"}]若是应用还没有被加载,那么应用控制器会首先使用 application:load/1 加载它。它会检查 applications 键对应的值,来确保要在该应用运行以前启动的应用都启动了。
而后应用控制器为应用建立一个应用主程序。它是该应用中全部进程的队长。应用主程序经过调用应用模块中的回调函数 start/2 启动应用(会给出由在 .app 文件中的 mod 建定义的启动参数)。
中止一个应用,但不卸载,可调用:
7> application:stop(ch_app).
ok
配置应用¶
可使用配置参数来对应用进行配置。它们在 .app 文件中是一个由键 env 指定的 {Par, Val} 元组列表。
{application, ch_app,
[{description, "Channel allocator"},
{vsn, "1"},
{modules, [ch_app, ch_sup, ch3]},
{registered, [ch3]},
{applications, [kernel, stdlib, sasl]},
{mod, {ch_app,[]}},
{env, [{file, "/usr/local/log"}]}
]}.
Par 必须是一个原子, Val 能够是任意值。应用能够经过调用 application:get_env(App, Par) 或一些其余相似函数来获取配置参数的值,参见 application(3) 。
例如:
% erl
Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0]
Eshell V5.2.3.6 (abort with ^G)
1> application:start(ch_app).
ok
2> application:get_env(ch_app, file).
{ok,"/usr/local/log"}.app 文件中的值能够被系统配置文件中的值所覆盖。系统配置文件是一个包含相关应用的配置参数的文件。
[{Application1, [{Par11,Val11},...]},
...,
{ApplicationN, [{ParN1,ValN1},...]}].
系统配置要被命名为 Name.config 而且要使用命令行参数 -config Name 来启动Erlang。更多信息参见 config(4) 。
例如:建立一个文件 test.config 包含一下内容:
[{ch_app, [{file, "testlog"}]}].
file 的值将覆盖在 .app 文件中所定义的 file 的值:
% erl -config test
Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0]
Eshell V5.2.3.6 (abort with ^G)
1> application:start(ch_app).
ok
2> application:get_env(ch_app, file).
{ok,"testlog"}若是使用了 发布处理 ,那么只能使用一个系统配置文件同时该文件必须叫作 sys.config 。
在 .app 文件中的值,也包括系统配置文件中的值,均可以直接在命令行中被覆盖:
% erl -ApplName Par1 Val1 ... ParN ValN例如:
% erl -ch_app file '"testlog"'
Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0]
Eshell V5.2.3.6 (abort with ^G)
1> application:start(ch_app).
ok
2> application:get_env(ch_app, file).
{ok,"testlog"}应用启动类型¶
当启动应用的时候要定义一个启动类型。
application:start(Application, Type)
application:start(Application) 和调用 application:start(Application, temporary) 是同样的。类型还能够是 permanent 持久的或者 transient 过渡的:
•若是一个持久应用终止了,全部其余的应用以及运行时系统都会被终止。
•若是一个过渡应用以 normal 理由终止了,那么这个信息会被上报可是不会终止其余应用。若是一个过渡应用异常终止了——即以非 normal 的理由终止了——那么其余应用以及运行时环境也会被终止。
•若是一个临时(temporary)应用终止了,那么会报告该信息但不会终止其余应用。
咱们老是能够经过明确调用 application:stop/1 来中止一个应用。不管是什么模式,都不会影响其余应用。
注意在实践中不多使用过渡模式,由于当一个监督树终止了,退出理由会被设置为 shutdown ,而非 normal 。
http://erlang.shiningray.cn/otp-design-principles/applications.htmlshell