我有一个名为bundleA
的活动bundle,它用另一个bundle中的doSomething()
方法实现了一个名为主Example
的类。ExampleImpl
实现Example
并通过ServiceLoader
加载(得益于SPI Fly)。在bundleA
的ExampleImpl.doSomething()
中,我需要获得调用doSomething()
的捆绑包的BundleWiring
(由于我无法更改API,因此不通过Bundle
或BundleContext
)。我可以得到bundleA
的BundleWiring
,但不能得到调用捆绑包的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
,就可以获得调用捆绑包的Bundle
和BundleWiring
。
你不能这么做。OSGi根本不干预跨捆绑包方法调用,因此您唯一可以用来尝试获取这些信息的是使用Thread.currentThread().getStackTrace()
访问的Java调用堆栈。然而,返回的StackTraceElement
对象只提供类名,而不是java.lang.Class
对象,因此无法将这些对象关联回bundle。
除了不可能之外,我非常怀疑这是否是一个好主意。根本不应该导出实现类,更不用说试图使它们对调用者敏感。
如果您需要实现对调用捆绑包敏感的行为,那么实现这一点的规范而正确的方法是使用ServiceFactory
接口注册服务。
您可以使用BundleTracker并对正在安装的所有WAB做出反应。然后您可以内省每个WAB,例如扫描类中的注释。
声明性服务和现有的WAB支持就是这样工作的。不过,编写这样一个扩展程序并不容易。
您说过不能更改API。但你能更改呼叫捆绑包吗?如果是这样的话,那么您可以使用一个"代理"服务来调用bundle,而不是原来的服务。然后,您可以将Bundle
和/或BundleContext
传递给代理服务,并将依赖关系逻辑放在那里。
想到的另一个选项是使用ThreadLocal
变量将此信息传递给被调用的bundle,但我不确定这种方法可能会产生什么副作用。