squbs 带有一个默认的引导类 org.squbs.unicomplex.Bootstrap。可以从IDE、命令行、sbt、甚至Maven启动。引导程序扫描类加载器并在每个加载的 jar 包中查找META-INF/squbs-meta.<ext>。如果 squbs 元数据可用, 则 jar 包将被视为 squbs cube或扩展, 并根据元数据声明进行初始化。然后, 引导程序首先初始化扩展、cubes, 然后是服务处理程序, 而不管它们在类路径中的顺序如何。
在正常情况下, 引导细节没有多大意义。然而,可能需要以编程方式用不同的方案引导 squbs。这在需要自定义配置且需要并行运行的测试用例中尤其常见。有关详细信息, 请参阅测试。引导 squbs 的语法如下:
选项1)使用自定义配置启动
UnicomplexBoot(customConfig)
.createUsing {(name, config) => ActorSystem(name, config)}
.scanResources()
.initExtensions
.stopJVMOnExit
.start()
选项2)使用默认配置启动
UnicomplexBoot {(name, config) => ActorSystem(name, config)}
.scanResources()
.initExtensions
.stopJVMOnExit
.start()
1.创建UnicomplexBoot (boot)对象。通过传入一个自定义配置或者ActorSystem创建闭包给UnicomplexBoot.apply(),完成。
2.在上面的示例中显示为 customConfig 的配置对象。它是一个从Typesafe Config 库的解析函数获取的配置对象。此配置对象尚未与reference.conf合并。它是可选的,替代其它 application.conf 配置中的定义。
3.传入一个函数或闭包来创建ActorSystem。实际创建发生在启动阶段(下面第7项)。默认的函数是{(name, config) => ActorSystem(name, config)}。传入的名称是从配置文件中读取的ActorSystem名称。这个config是所有配置合并后加载的配置对象。大多数用例都希望以这种方式创建 ActorSystem, 因此不需要提供函数。createUsing可以完全避免。
4.使用scanResources()函数扫描组件查找cubes、服务或者扩展。这是强制性的, 否则将不启动任何组件。如果没有传递参数, squbs 引导程序将扫描其类加载器。测试用例可能希望只针对某些组件进行扫描。可以传入另外的squbs-meta.conf文件位置(作为scanResources的一个变量参数),例如.scanResources("component1/META-INF/squbs-meta.conf", "component2/META-INF/squbs-meta.conf")。将扫描你的类路径以及另外所给资源。如果你不想扫描类路径,传入withClassPath = false 或者在资源列表前的第一个参数仅传入false:.scanResources(withClassPath = false, "component1/META-INF/squbs-meta.conf", "component2/META-INF/squbs-meta.conf")。
5.使用initExtension函数初始化扩展。将初始化扫描到的所有扩展。扩展的初始化将在ActorSystem创建前完成。对于多个Unicomplex用例(即多个ActorSystem),同一扩展不能多次初始化。一个扩展只能由一个测试用例使用。在某些测试用例中, 我们根本不希望初始化扩展, 也不会调用 initExtension。
6.在退出时停止 JVM。这是通过调用stopJVMOnExit函数来启用的。通常不应将此选项用于测试用例。它是由 squbs 的引导使用, 以确保 squbs 关闭和正确退出。
7.通过调用start()启动Unicomplex。这是一个强制性的步骤。没有它,没有ActorSystem启动,没有Actor运行。在系统完全启动和运行之前, start调用会阻塞或者产生一个超时。当启动超时时, 某些组件可能仍在初始化, 使系统处于Initializing状态。然而,任何单个组件故障都将使系统在超时时状态为Failed。这将允许系统组件 (如系统诊断程序) 运行并完成。默认的启动超时设置为60秒。对于预期超时的测试, 可以设置更小的值,通过向start()传入要求的超时,例如start(Timeout(5 seconds))或更短的start(5 seconds)(使用从duration到timeout的隐式转换)。
配置解析
squbs 选择一个应用程序配置, 并将其与类路径下的聚合的application.conf和reference.conf合并。正在合并的应用程序配置从以下顺序选择:
1.如果创建boot对象时提供了一个配置,这个配置将被选中。即上例中的customConfig字段。
2.如果在外部配置目录中提供了application.conf文件, 则此application.conf将被选中。外部配置目录是通过设置squbs.external-config-dir来配置的,默认是squbsconfig。不可以通过提供的配置或外部配置来更改或重写此目录(因为目录本身是使用配置属性确定的)。
3.否则,将使用与应用程序一起提供的application.conf(如果有将使用)。然后,回到reference.conf。
模块化系统
squbs将应用划分到称为cube的模块中。squbs中的模块旨在以模块化隔离以及类路径上运行。模块隔离目的在真正的模块间松耦合,不会由于依赖出现任何类路径冲突。
当前实现的引导程序,来自于类路径。在引导时,squbs通过类路径扫描自动检测模块。扫描到的cube自动被检测并启动。
Cube Jar包
所有cube由一个含有cube逻辑的顶级jar包表示。都必须有cube元数据,存在于META-INF/squbs-meta.<ext>。支持的扩展名包括.conf, .json, .properties。格式遵守Typesafe配置格式。
至少,cube元数据唯一标识cube和版本,并声明以下一个或多个:
Actor:标识 squbs 自动启动的众所周知的actor。
Service:标识一个squbs服务。
Extension:标识一个squbs框架扩展。扩展入口点必须继承于org.squbs.lifecycle.ExtensionLifecycle特质。
配置解析
为一个cube提供application.conf,当多个cube试图提供它们内部的application.conf会导致问题。合并此类配置的优先级规则没有定义。推荐cube仅提供一个reference.conf,并且可以被外部application.conf覆盖以进行部署。
众所周知的actor
Well known actor只是Akka文档所定义的Akka actors。它们由一个监管actor(为每一个cube创建)启动。监管者持有cube名称。因此,任何well known actor有一个/<CubeName>/<ActorName>路径,并且可以使用ActorSelection调用(使用/user/<CubeName>/<ActorName>)。
一个well known actor可以由单例actor或者路由器启动。为了将一个well known actor声明为一个路由器,在actor声明中增加with-router = true。对于well known actor路由器、调度器和邮件按照Akka文档配置在reference.conf 或application.conf 。
下面是一个META-INF/squbs-meta.conf中的cube声明,申明了一个well known actor:
cube-name = org.squbs.bottlecube
cube-version = "0.0.2"
squbs-actors = [
{
class-name = org.squbs.bottlecube.LyricsDispatcher
name = lyrics
with-router = false # Optional, defaults to false
init-required = false # Optional
}
]
init-required的参数用于需要发回其完全初始化状态的actor, 以便将系统视为已初始化。有关启动/初始化挂钩的完整讨论, 请参阅运行时生命周期和 API 文档的启动挂钩部分。
如果一个actor配置了with-router (with-router = true)和一个非默认调度器,通常意味着在非默认调度器上安排actor(即rootee)。路由器将假定well known actor名称, 而不是 routee (你的actor实现)。路由器上设置的调度器只会影响路由器, 而不是 routee。要影响 routee, 您需要为 routees 创建一个单独的配置, 并将 "/*" 追加到该名称。接下来, 您要将 routee 中的调度器配置为下面的示例。
akka.actor.deployment {
# Router configuration
/bottlecube/lyrics {
router = round-robin-pool
resizer {
lower-bound = 1
upper-bound = 10
}
}
# Routee configuration. Since it has a '*', the name has to be quoted.
"/bottlecube/lyrics/*" {
# Configure the dispatcher on the routee.
dispatcher = blocking-dispatcher
}
Akka文档中记录了路由器概念、示例和配置。
服务
在实现HTTP(s)服务章节对服务有详细描述。在META-INF/squbs-meta.conf申明服务元数据,如下例所示:
cube-name = org.squbs.bottlesvc
cube-version = "0.0.2"
squbs-services = [
{
class-name = org.squbs.bottlesvc.BottleSvc
web-context = bottles # You can also specify bottles/v1, for instance.
# The listeners entry is optional, and defaults to 'default-listener'.
listeners = [ default-listener, my-listener ]
# Optional, defaults to a default pipeline.
pipeline = some-pipeline
# Optional, disables the default pipeline if set to off. If missing, it is set to on.
defaultPipeline = on
# Optional, only applies to actors.
init-required = false
}
]
请看服务注册有详细描述。
扩展
squbs中的扩展是为了环境需要启动的低级别设施。扩展初始化器需要继承于org.squbs.lifecycle.ExtensionLifecycle特质并覆盖合适的回调。扩展有很大的能力来内省系统,并提供额外的功能,而这些squbs本身并没有提供。在同一个cube中,不能将扩展与actor或服务组合在一起。
扩展依次开始, 一个接着一个。扩展的提供者可以在扩展申明中提供一个序列号码在扩展启动时指定:sequence = [number]。如果没有指定序列号,则默认为Int.maxValue。这意味着它将在所有提供序列号的扩展之后启动。如果有多个扩展不指定序列号或指定相同的序列号, 则启动这些扩展的顺序是随机的。关机顺序与启动顺序相反。
关闭squbs
squbs运行时,可以向Unicomplex()发送GracefulStop消息来正确关闭squbs。
默认的启动主方法,org.squbs.unicomplex.Bootstrap,注册了一个JVM关闭钩子。因此,如果一个squbs应用使用了默认的main方法启动,当JVM收到SIGTERM时,会优雅的关闭。
如果某个其他监视进程负责关闭应用程序 (例如 JSW), 则可以将 org.squbs.unicomplex.Shutdown 设置为正常关闭系统的主要方法。此Shutdown main 方法也向 Unicomplex 发送 GracefulStop 消息。
在某些用例中, 最好为关机添加延迟。例如, 如果负载平衡器每5秒钟检查一次应用程序的运行状况, 并且应用程序在运行状况检查后关闭1秒, 应用程序将在接下来的4秒内继续收到请求, 直到下一次健康检查为止;但是, 它无法满足这些请求。如果使用上述方法之一 org.squbs.unicomplex.Bootstrap 或 org.squbs.unicomplex.Shutdown, 则可以通过在配置中添加以下内容来增加关机的延迟:
squbs.shutdown-delay = 5 seconds
有了以上配置,向Unicomplex发送的GracefulStop消息将按计划推迟5秒发送。
在收到GracefulStop消息后,Unicomplex actor将停止服务并传播GracefulStop消息给所有的cube监管者。每一个监管者负责停止它cube内的actor(通过传播GracefulStop消息给它的想要优雅停止的孩子),确认它们成功的停止或者在超时后发送一个PoisonPill,然后停止它自己。一旦所有的cube监管者和服务停止,squbs系统关闭。然后,一个关闭钩将被调用,来停止所有的扩展并最终退出JVM。
web 容器目前没有标准的控制台, 允许 squbs 的用户自己构建。通过向Unicomplex发送停止消息, web 控制台可以提供正确的用户关闭, 如下所示:
Unicomplex() ! GracefulStop