繁体   English   中英

将Bundle-A jar文件安装到OSGi容器后,如何调用其中一个方法

[英]How to call one of the methods in my Bundle-A jar file after it has been installed into OSGi container

我最近开始研究OSGi框架。 我有一个名为Bundle-A的包。 我想从我的主应用程序中调用Bundle-A jar中的一个方法。

我从我的主应用程序加载并安装了Bundle-A。 下面是我的主要应用程序的代码,我在这里安装Bundle-A。

private void initializeModelFramework() {

    try {

        FileUtils.deleteDirectory(new File("felix-cache"));
        FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next();

        Framework framework = frameworkFactory.newFramework(new HashMap<String, String>());
        framework.start();

        BundleContext bundleContext = framework.getBundleContext();

        modulesNameVersionHolder.put("Bundle-A", "1.0.0");

        List<Bundle> installedBundles = new LinkedList<Bundle>();

        String basePath = "C:\\ClientTool\\LocalStorage";

        for (Map.Entry<String, String> entry : modulesNameVersionHolder.entrySet()) {
            String version = entry.getValue();
            final String filename = name + Constants.DASH + version + Constants.DOTJAR;
            final String localFilename = GoldenModulesConstants.FILE_PROTOCOL + basePath+ File.separatorChar + filename;

            installedBundles.add(bundleContext.installBundle(localFilename));
        }   

        for (Bundle bundle : installedBundles) {
            bundle.start();// this will start bundle A
        }

        // After starting the Bundle-A, now I need to call one of the methods in Bundle-A
        for(int i=0; i<=10; i++) {
            //call processingEvents method of Bundle-A class GoldenModelFramework
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

现在Bundle-A已经启动了。 下面是我对Bundle-A的Activator类。

public class Activator implements BundleActivator {

    private static final String BUNDLE_VERSION_KEY = "Bundle-Version";
    private static Logger s_logger = Logger.getLogger(Activator.class.getName());

    @Override
    public void start(BundleContext context) throws Exception {

        final Bundle bundle = context.getBundle();
        final String bundleName = bundle.getSymbolicName();
        final String bundleVersion = (String) bundle.getHeaders().get(BUNDLE_VERSION_KEY);

        System.out.println(bundleName+" - "+bundleVersion);
    }

    @Override
    public void stop(BundleContext context) throws Exception {
            System.out.println("Bye.!");
    }
}

以下是我在Bundle-A jar中的课程。 一旦Bundle-A启动,我需要从上面的主应用程序代码中调用processingEvents方法。

public class GoldenModelFramework {

    private static final Logger LOGGER = Logger.getLogger(GoldenModelFramework.class.getName());
    private static final long checkingAfterEveryXMinutes = 15L;


    public GoldenModelFramework() {
        // following the traditions
    }

    public static void processingEvents(final String item) {

        for (BundleRegistration.HolderEntry entry : BundleRegistration.getInstance()) {
            final String response = entry.getPlugin().process(item);
            System.out.println(response);
        }
    }
}

我不确定这样做的正确方法是什么? 我知道一种方法是在我的主应用程序pom.xml文件中添加此Bundle-A的依赖项,因为我正在使用基于maven的项目。 但我不认为这是正确的做法。 因为最终,我将有更多的捆绑,所以应该有一些其他方法,我不知道。

我应该在这里使用ServiceListener或ServiceTracker吗? 我的代码的任何简单的示例基础将帮助我更好地理解。 谢谢。

我希望这个问题足够清楚。 我试图在Bundle-A加载并安装后调用其中一个方法。

你有几个选择:

动态导入包

您可以使用DynamicImport-Package而不是Import-Package。 在这种情况下,当主包启动时,bundle-A不必处于活动状态。 虽然这有效但我不推荐这个解决方案,因为我不喜欢DynamicImport-Package。 在这种情况下,当然捆绑包A必须是主捆绑包的依赖关系。

用反射

您可以使用反射调用所需的方法,如下所示(草稿示例):

Class<GoldenModelFramework> clazz = bundleA.loadClass("GoldenModelFramework");
Method m = clazz.getMethod("processingEvents", String.class);
m.execute(null, myParam);

这有点好,但是这个解决方案仍然有点模糊,我不会说这是一个干净的代码。

使用接口和OSGi服务

最干净的方式需要一些重构。 在这种情况下,您应该创建一个接口,并在bundle A的Activator中,您应该基于该接口注册服务。 在主捆绑中,您应该使用服务跟踪器来捕获该服务并在其上调用该方法。

如果你真的想让你的方法processEvent静态,那么注册的服务对象(基于接口)应该只是调用内部的静态方法。

没有必要将bundle A作为依赖关系添加到主bundle中,接口应该被带入第三个bundle,它是main和A bundle的依赖关系。

虽然这个解决方案似乎是最复杂的,但我会建议这个。

一个例子:

创建一个界面并将其放到像goldenframework-api这样的新包中。

public interface GoldenModelFrameworkOSGi {
    void processingEvents(final String item);
}

goldenframework-api将是主bundle和bundle-A的依赖。 主捆绑包将使用它,而捆绑包A将实现它。

以下是bundle A如何实现它:

public class GoldenFrameworkOSGiImpl {
    public void processingEvents(final String item) {
        GoldenModelFramework.processEvents(item);
    }
}

在bundle-A中创建一个Activator类(我将在激活器中省略你的代码以减少输入):

public class Activator {
  private ServiceRegistration goldenFrameworkSR;

  @Override
  public void start(BundleContext context) {
    goldenFrameworkSR = context.registerService(GoldenFrameworkOSGi.class, new GoldenFrameworkOSGi(), new HashTable());
  }

  @Override
  public void stop(BundleContext context) {
    goldenFrameworkSR.unregister();
  }
}

如你所知,Bundle-A的代码你可以作弊。 当bundle-A处于Active状态时,您可以确保注册所需的服务。 但是,在将来,您应该考虑基于事件(例如使用ServiceTracker)进行工作。 我的意思是这将是一个不好的做法:):

ServiceReference sr = context.getServiceReference(GoldenServiceOSGi.class);
GoldenServiceOSGi gs = context.getService(sr);
gs.processEvents(...);
context.ungetService(sr);

这可能会解决您现在的问题,您可以继续工作。 但是,请考虑阅读像“OSGi in Action”这样的书,以了解OSGi捆绑和服务生命周期,以便您可以重新设计框架。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM