如何在OSGi中获取调用Bundle的BundleWiring



我有一个名为bundleA的活动bundle,它用另一个bundle中的doSomething()方法实现了一个名为主Example的类。ExampleImpl实现Example并通过ServiceLoader加载(得益于SPI Fly)。在bundleAExampleImpl.doSomething()中,我需要获得调用doSomething()的捆绑包的BundleWiring(由于我无法更改API,因此不通过BundleBundleContext)。我可以得到bundleABundleWiring,但不能得到调用捆绑包的BundleWiring:

Bundle bundleA = FrameworkUtil.getBundle(ExampleClass.class);
BundleWiring bundleWiringOfBundleA = bundle.adapt(BundleWiring.class);

如何获取调用捆绑包的BundleWiring

在我的特定情况下,调用捆绑包将始终是一个WAB,它恰好在Liferay Portal 7.0中运行。因此,如果有一个特定于LiferayPortal的解决方案,我会接受,但一个更通用的OSGi解决方案也可以。

请注意,我想要调用bundle的bundle布线,而不是依赖于当前bundle布线的每个bundle的线束布线。我知道我可以获得依赖于当前线束的线束,但这无助于我获得调用线束:

Bundle bundleA = FrameworkUtil.getBundle(ExampleClass.class);
List<BundleWires> bundleWires =
bundleWiring.getProvidedWires(BundleRevision.PACKAGE_NAMESPACE);
bundleWires.get(0).getRequirerWiring();

在Liferay中,调用WAB的BundleContext作为"osgi-bundlecontext":存储在ServletContext

BundleContext bundleContext = servletContext.getAttribute("osgi-bundlecontext");
Bundle bundle = bundleContext.getBundle();
BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);

因此,只要您可以访问Liferay中的ServletContext,就可以获得调用捆绑包的BundleBundleWiring

你不能这么做。OSGi根本不干预跨捆绑包方法调用,因此您唯一可以用来尝试获取这些信息的是使用Thread.currentThread().getStackTrace()访问的Java调用堆栈。然而,返回的StackTraceElement对象只提供类名,而不是java.lang.Class对象,因此无法将这些对象关联回bundle。

除了不可能之外,我非常怀疑这是否是一个好主意。根本不应该导出实现类,更不用说试图使它们对调用者敏感。

如果您需要实现对调用捆绑包敏感的行为,那么实现这一点的规范而正确的方法是使用ServiceFactory接口注册服务。

您可以使用BundleTracker并对正在安装的所有WAB做出反应。然后您可以内省每个WAB,例如扫描类中的注释。

声明性服务和现有的WAB支持就是这样工作的。不过,编写这样一个扩展程序并不容易。

您说过不能更改API。但你能更改呼叫捆绑包吗?如果是这样的话,那么您可以使用一个"代理"服务来调用bundle,而不是原来的服务。然后,您可以将Bundle和/或BundleContext传递给代理服务,并将依赖关系逻辑放在那里。

想到的另一个选项是使用ThreadLocal变量将此信息传递给被调用的bundle,但我不确定这种方法可能会产生什么副作用。

相关内容

  • 没有找到相关文章

最新更新