簡體   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