嵌入式 OSGi:访问动态加载的包组件
Embedded OSGi: accessing dynamically loaded bundle components
在处理将 OSGi 嵌入 application/library、在运行时加载捆绑包然后在主机中使用该捆绑包时,我有点不知所措 application/library。
这是从我的主机加载包的代码:
// framework is the embedded OSGi framework
Bundle b = framework.getBundleContext().installBundle( "file:/project_dir/bundle/MyBundle.jar" );
b.start();
捆绑包包含一些非常简单的东西:
public class Activator implements BundleActivator
{
@Override
public void start( BundleContext context )
{
}
@Override
public void stop( BundleContext context )
{
}
public String shout()
{
return "let it all out";
}
}
如何从主机应用程序访问 shout() 方法?
简而言之:
- 将您的对象注册为 OSGi 服务
- 在启动嵌入式 OSGi 容器的 application/library 中获取 OSGi 服务
更详细的解决方案:
- 在包含 shout() 函数的单独 jar 中定义接口
- 将 jar 文件放在 application/library
的 class 路径上
- 在你的 bundle
的 Activator class 中实现接口
- 将 Activator 的实例class注册为基于接口的 OSGi 服务
- 在application/library中,根据接口获取OSGi服务
或者,如果您没有 application/library 中的接口,您仍然可以获取 OSGi 服务并使用反射调用函数。
以下是关于上一个答案后要使用的代码的一些详细信息:
包含您的方法的接口。
public interface MyInterface {
String shout();
}
您会注意到,为您的库准备两个包是一种很好的方法:一个用于接口,另一个用于实现。当实施包来来去去时,它将防止出现 "refresh packages" 问题。
上一个接口的实现:
public class MyImpl implements MyInterface {
public String shout() {
return "let it all out";
}
}
实现的包不需要被bundle导出。 class MyImpl
不会被服务消费者直接使用。
激活器新密码:
public class Activator implements BundleActivator {
private ServiceRegistration serviceRegistration;
@Override
public void start( BundleContext context ) {
this.serviceRegistration = context.registerService(
MyInterface.class,
new MyImpl(), new HashMap<String,String>());
}
@Override
public void stop( BundleContext context ) {
if (serviceRegistration!=null) {
serviceRegistration.unregister();
}
}
}
包含激活器和实现的包需要在其文件中导入接口包MANIFEST.MF
。激活器的包或实现都不需要在此文件中导出。它们必须保留在捆绑包内部。
class 从另一个 bundle 使用服务
public void callService() {
ServiceReference<MyInterface> reference
= bundleContext.getServiceReference(MyInterface.class);
MyInterface foo = bundleContext.getService(reference);
try {
//use service
String msg = service.shout();
} finally {
bundleContext.ungetService( reference );
}
}
你可以注意到消费者只需要导入接口包(而不是实现包)。此外,您需要小心处理 OSGi 的动态。该服务本可以在两次通话之间进行!
希望对你有帮助,
蒂埃里
在处理将 OSGi 嵌入 application/library、在运行时加载捆绑包然后在主机中使用该捆绑包时,我有点不知所措 application/library。
这是从我的主机加载包的代码:
// framework is the embedded OSGi framework
Bundle b = framework.getBundleContext().installBundle( "file:/project_dir/bundle/MyBundle.jar" );
b.start();
捆绑包包含一些非常简单的东西:
public class Activator implements BundleActivator
{
@Override
public void start( BundleContext context )
{
}
@Override
public void stop( BundleContext context )
{
}
public String shout()
{
return "let it all out";
}
}
如何从主机应用程序访问 shout() 方法?
简而言之:
- 将您的对象注册为 OSGi 服务
- 在启动嵌入式 OSGi 容器的 application/library 中获取 OSGi 服务
更详细的解决方案:
- 在包含 shout() 函数的单独 jar 中定义接口
- 将 jar 文件放在 application/library 的 class 路径上
- 在你的 bundle 的 Activator class 中实现接口
- 将 Activator 的实例class注册为基于接口的 OSGi 服务
- 在application/library中,根据接口获取OSGi服务
或者,如果您没有 application/library 中的接口,您仍然可以获取 OSGi 服务并使用反射调用函数。
以下是关于上一个答案后要使用的代码的一些详细信息:
包含您的方法的接口。
public interface MyInterface { String shout(); }
您会注意到,为您的库准备两个包是一种很好的方法:一个用于接口,另一个用于实现。当实施包来来去去时,它将防止出现 "refresh packages" 问题。
上一个接口的实现:
public class MyImpl implements MyInterface { public String shout() { return "let it all out"; } }
实现的包不需要被bundle导出。 class
MyImpl
不会被服务消费者直接使用。激活器新密码:
public class Activator implements BundleActivator { private ServiceRegistration serviceRegistration; @Override public void start( BundleContext context ) { this.serviceRegistration = context.registerService( MyInterface.class, new MyImpl(), new HashMap<String,String>()); } @Override public void stop( BundleContext context ) { if (serviceRegistration!=null) { serviceRegistration.unregister(); } } }
包含激活器和实现的包需要在其文件中导入接口包
MANIFEST.MF
。激活器的包或实现都不需要在此文件中导出。它们必须保留在捆绑包内部。class 从另一个 bundle 使用服务
public void callService() { ServiceReference<MyInterface> reference = bundleContext.getServiceReference(MyInterface.class); MyInterface foo = bundleContext.getService(reference); try { //use service String msg = service.shout(); } finally { bundleContext.ungetService( reference ); } }
你可以注意到消费者只需要导入接口包(而不是实现包)。此外,您需要小心处理 OSGi 的动态。该服务本可以在两次通话之间进行!
希望对你有帮助, 蒂埃里