我有一个名为bundleA
的活动包,它使用另一个包中名为Example
的方法实现了一个名为doSomething()
的类。 ExampleImpl
实施Example
并通过ServiceLoader
装载(感谢SPI Fly)。在来自ExampleImpl.doSomething()
的bundleA
中,我需要得到BundleWiring
的doSomething()
(没有通过Bundle
或BundleContext
,因为我无法更改API)。我可以得到bundleA
的BundleWiring
,但不是调用包的BundleWiring
:
Bundle bundleA = FrameworkUtil.getBundle(ExampleClass.class);
BundleWiring bundleWiringOfBundleA = bundle.adapt(BundleWiring.class);
我怎样才能获得调用包的BundleWiring
?
在我的特定情况下,调用包将始终是一个恰好在Liferay Portal 7.0中运行的WAB。因此,如果有一个特定于Liferay Portal的解决方案,我会接受,但更通用的OSGi解决方案也可以。
请注意,我希望调用捆绑包的捆绑连接不是每个捆绑包的捆绑连接,这取决于当前捆绑连接。我知道我可以获得依赖于当前捆绑接线的捆绑接线,但这不能帮助我专门获取调用捆绑包:
Bundle bundleA = FrameworkUtil.getBundle(ExampleClass.class);
List<BundleWires> bundleWires =
bundleWiring.getProvidedWires(BundleRevision.PACKAGE_NAMESPACE);
bundleWires.get(0).getRequirerWiring();
你不能这样做。 OSGi根本不介入跨包方法调用,因此您可以尝试获取此信息的唯一方法是使用Thread.currentThread().getStackTrace()
访问的Java调用堆栈。但是,返回的StackTraceElement
对象只会为您提供类名而不是java.lang.Class
对象,因此无法将这些对象关联回束。
除了不可能,我非常怀疑这将是一个好主意。您根本不应该导出实现类,更不用说尝试使它们对调用者敏感。
如果您需要实现对调用bundle敏感的行为,那么实现该行为的规范和正确方法是使用ServiceFactory
接口注册服务。
您可以使用BundleTracker并对正在安装的所有WAB做出反应。然后,您可以内省每个WAB,例如扫描类以进行注释。
声明性服务和现有的WAB支持以这种方式工作。编写这样的扩展器并不容易。
你说你不能改变API。但你可以改变呼叫捆绑吗?如果是这样,那么您可以使用“代理”服务来调用捆绑包而不是原始捆绑包。然后,您可以将Bundle
和/或BundleContext
传递给代理服务,并将您的依赖逻辑放在那里。
想到的另一个选择是使用ThreadLocal
变量将此信息传递给被调用的bundle,但我不确定该方法可能具有哪些副作用。
在Liferay中,调用WAB的BundleContext
作为ServletContext
存储在"osgi-bundlecontext"
中:
BundleContext bundleContext = servletContext.getAttribute("osgi-bundlecontext");
Bundle bundle = bundleContext.getBundle();
BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
因此,只要您可以访问Liferay中的ServletContext
,您就可以获得调用包的Bundle
和BundleWiring
。