我目前正被OSGI弄湿,并决定使用一个稍微非典型的OSGI用例。我想在命令行应用程序中使用它。我想要一个main(..)
方法,它接受一些标志和参数,执行一些操作并再次关闭。我不想启动ApacheKaraf(或类似的)并在OSGI控制台中运行命令(不过这可能会成为一个可选功能)。
为什么OSGI首先用于命令行应用程序?应用程序应该使用同一库的不同版本(即弹性搜索)。当然,这只是因为它很糟糕。
我应该在捆绑包内还是在外部使用服务?一个人会怎么做?可能会出现什么问题?
使用bnd时,有一种非常简单的方法可以编写命令行应用程序。bnd有一个用package命令创建可执行jar的功能:
$ bnd run xyz.bnd
.... whatever your app does
$ bnd package xyz.bnd
$ ls
xyz.jar xyz.bnd .....
$ java -jar xyz.jar ...
.... whatever your app does
请注意,这个jar是完整的,它包含所有的bundle、框架、启动器和运行它的属性。没有外部依赖关系。
诀窍是获取主线程(在其中调用静态main)。您只需要注册一个具有属性main.thread=true
的Runnable服务。然后,启动器将在此服务上调用run(),然后退出(您可以在运行中停留多久)。
要获取命令行参数,可以获取具有launcher.arguments
属性的Object服务。此属性将包含您的命令参数。或者使用DS组件:
@Component(immediate=true, property="main.thread=true")
public class Main implements Runnable {
String[] args;
public void run(){ ... }
@Reference(target="(launcher.arguments=*)")
void setArgs(Object service, Map<String,Object> props) {
this.args = (String[]) props.get("launcher.arguments");
}
}
最好的方法是使用bndtools,因为它可以轻松地测试/调试代码。那么你可能想使用bndrun文件。
附言:在最新的bnd中,您可以使用Callable<整数>而不是Runnable。返回值就是进程的退出代码。然而,这可能还没有出现在bndtools中。
回答我自己的问题(问答风格):我目前认为最好是
- 启动嵌入的OSGI(clean)
- 启动容器
- 导出API程序包(
org.osgi.framework.system.packages.extra
) - 安装并启动所需的捆绑包
- 使用OSGI之外的服务
- 关闭容器
- 退出应用程序
在所有捆绑包启动后,可以放心地假设所需的服务可用。这也避免了将配置传递到OSGI中,而OSGI实际上只是服务调用的参数。