嵌入式OSGi:访问动态加载的bundle组件

时间:2015-02-27 20:40:54

标签: java runtime osgi bundle

在处理将OSGi嵌入到应用程序/库中,在运行时加载bundle然后在宿主应用程序/库中使用该bundle时,我有点迷失。

这是从我的主机加载捆绑包的代码:

// 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()方法?

2 个答案:

答案 0 :(得分:2)

简而言之:

  • 将对象注册为OSGi服务
  • 在启动嵌入式OSGi容器的应用程序/库中获取OSGi服务

更详细的解决方案:

  • 在包含shout()函数的单独jar中定义接口
  • 将jar文件放在应用程序/库的类路径中
  • 在捆绑包的Activator类中实现接口
  • 基于接口
  • 将Activator类的实例注册为OSGi服务
  • 在应用程序/库中,根据界面
  • 获取OSGi服务

或者,如果您没有应用程序/库中的接口,您仍然可以获得OSGi服务并使用反射调用该函数。

答案 1 :(得分:2)

以下是有关在上一个答案后使用的代码的一些详细信息:

  • 包含您的方法的界面。

    public interface MyInterface {
        String shout();
    }
    

    您可以注意到,为您的库提供两个捆绑包是一个很好的方法:一个用于接口,另一个用于实现。它将防止有"刷新包"当实施包再次出现时会出现问题。

  • 上一个界面的实现:

    public class MyImpl implements MyInterface {
        public String shout() {
            return "let it all out";
        }
    }
    

    实施包不需要由捆绑导出。课程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();
            }
        }
    }
    

    包含激活器和实现的bundle需要在其文件MANIFEST.MF中导入接口的包。激活器的包或实现都不需要在此文件中导出。它们必须保持在捆绑内部。

  • 从另一个包中使用该服务的类

    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的动态。这项服务可能在两次通话之间进行!

希望它可以帮到你, 亨利