Java 如何在将jar文件安装到OSGi容器后调用Bundle中的一个方法

Java 如何在将jar文件安装到OSGi容器后调用Bundle中的一个方法,java,maven,osgi,osgi-bundle,Java,Maven,Osgi,Osgi Bundle,我最近开始研究OSGi框架。我有一个bundle-A。我想从我的主应用程序调用bundle-ajar中的一个方法 我已经从主应用程序加载并安装了Bundle-A。下面是我安装Bundle-A的主要应用程序的代码 private void initializeModelFramework() { try { FileUtils.deleteDirectory(new File("felix-cache")); FrameworkFactory frame

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

我已经从主应用程序加载并安装了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();
    }
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);
        }
    }
}
我不确定什么是正确的方法?我知道一种方法是在我使用基于maven的项目时,在我的主应用程序pom.xml文件中添加这个Bundle-A的依赖项。但我不这么认为这是正确的方法。因为最终,我会有更多的捆绑包,所以应该有一些其他的方法,我不知道

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


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

您有几种选择:

动态导入包

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

使用反射

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

goldenframeworkapi将是主bundle和bundle-a的依赖项。主bundle将使用它,而bundle-a将实现它

以下是bundle A如何实现它:

public class GoldenFrameworkOSGiImpl {
    public void processingEvents(final String item) {
        GoldenModelFramework.processEvents(item);
    }
}
在bundle-A中创建一个Activator类(我将省略该Activator中的代码以减少键入):

正如你所知道的Bundle-A的代码一样,你可以作弊一点。当bundle-A处于活动状态时,您可以确保您需要的服务已注册。但是,将来您应该考虑基于事件的工作(例如使用ServiceTracker)。我的意思是这将是一个糟糕的做法:):


这可能会暂时解决您的问题,您可以继续工作。但是,请考虑阅读一本书,比如“OSGi在行动中”,对OSGi捆绑和服务生命周期有一种感觉,这样你就可以重新设计你的框架了。你能在第三个例子的基础上给我一个简单的例子吗?通过这种方式,我将更容易理解并相应地编写代码。我对OSGi框架一无所知。谢谢你的帮助。用一个例子编辑了我的答案。请注意,我对你的问题和答案有一种奇怪的感觉。我展示了一些技巧,但是如果你更深入地研究OSGi世界,你可能会以一种甚至不需要这样技巧的方式设计代码。谢谢Balazs的建议。你能告诉我你对我的问题有什么疑问吗?通过这种方式,我可以想到我在设计中犯了什么错误,我还能做些什么来改进它。这是我的一种感觉。也许如果我看到背后的动机,我就会知道为什么我会有这种感觉。如果你不介意的话,我想说几件事。我不知道BundleRegistration类的用途是什么,但是用一个名为getInstance()的函数返回集合对我来说有些奇怪。另外,我猜GoldenFramework类有更多的方法,因为在本例中,它将是一个简单的Util类,通常有一个私有构造函数(因为Util类是不可实例化的)。但正如我所说的:框架背后的动机将是有趣的部分。从一个更方便的层次开始可能会更好,你现在正在尝试在爬行之前跑步。最简单的入门方法是使用bndtools。这是一个很好的起点:
public interface GoldenModelFrameworkOSGi {
    void processingEvents(final String item);
}
public class GoldenFrameworkOSGiImpl {
    public void processingEvents(final String item) {
        GoldenModelFramework.processEvents(item);
    }
}
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();
  }
}
ServiceReference sr = context.getServiceReference(GoldenServiceOSGi.class);
GoldenServiceOSGi gs = context.getService(sr);
gs.processEvents(...);
context.ungetService(sr);