【问题标题】:How to inject a CDI managed bean that exists in another classloader如何注入存在于另一个类加载器中的 CDI 托管 bean
【发布时间】:2015-04-12 23:30:32
【问题描述】:

我正在开发一个将在 Java EE 应用程序中使用的框架,因此很可能部署在 EAR 文件的 \lib 目录中。

该框架将使用 CDI 以编程方式查找和注入位于使用该框架的 Java EE 应用程序中的 bean。我遇到的问题是,当我的框架调用来自javax.enterprise.Provider<T>Provider.get() 方法来获取bean 的实例时,Weld 会抛出UnsatisfiedResolutionException

为了检查这不是与 CDI 相关的问题,我还尝试使用 MyClass myClass = Class.forName(clazz).newInstance(); 获取类的实例,但抛出了 ClassNotFoundException

我用于测试目的的EAR文件的结构如下:

MyTestApp.ear
+\lib\MyFramework.jar <----Contains the framework invoking the Provider.get() method
+MyTestApp.jar        <----Contains the bean I want to inject

我的测试应用程序的 EAR 包含一个 application.xml 文件,其中包括 &lt;library-directory&gt;lib&lt;/library-directory&gt;

我相信这个问题的发生是因为我要注入的 bean 存在于一个单独的类加载器中。即\lib\MyFramework.jarMyTestApp.jar 在不同的类加载器中。我发现了这个SO question,这似乎表明情况就是这样。鉴于我正在开发一个框架,我不认为问题中的答案是满足我需求的可行解决方案。

我很想知道创建 CDI 可移植扩展是否可以让我获得我想要使用的 bean 的实例,但在这方面没有足够的经验。使用@Observes ProcessAnnotatedType&lt;T&gt;,我可以在EAR 文件中看到存在于\lib 目录之外的bean,包括我想以编程方式注入的bean。

我的问题是:

  1. 我是否正确假设因为\lib\MyFramework.jarMyTestApp.jar 位于不同的类加载器中而发生此问题?

  2. 我可以使用 CDI 做些什么来让我的框架在部署在 EAR 文件的 \lib 目录中时调用 Provider.get() 方法以避免 Weld 抛出 UnsatisfiedResolutionException

  3. 在 CDI 之外我可以做些什么来达到相同的结果吗?


更新

我现在尝试将 MyFramework.jar 移动到 EAR 文件的根目录,并将 jar 模块包含在 application.xml 文件中,但由于 CDI 未满足依赖项异常,容器无法启动应用程序。当 MyFramework.jar 位于 \lib 目录中并且与我的问题中引用的 bean 不同时,可以注入异常中引用的 bean。

【问题讨论】:

  • 你提到了焊接。您要部署到什么容器?包括名称和版本。
  • 我有两个要部署到的应用服务器。第一个是运行 Weld 2.0.0 SP1 的 GlassFish 4。第二个是运行 Weld 2.2.10 SP1 的 GlassFish 4.1。

标签: java jakarta-ee classloader cdi weld


【解决方案1】:

1:是的

2 : 其实我不知道

3 : 是的,您必须了解 ear 类加载器的层次结构,ear lib 目录中的 jar 是在 ear 级别加载的,因此在所有子类加载器中都可用(ear 中的每个组件都有一个子类加载器)。

这意味着 MyFramework.jar 在 MyTestApp.jar 耳朵子类加载器中是可见的,但反之为假。

In java EE, which jars should I put in the library dir?

你可以:

  • 将 MyTestApp.jar 移动到 ear lib 目录(MyFramework.jar 可以在 lib dir 中并引用 MyTestApp.jar 或在 ear 根目录)
  • 将 MyFramework.jar 移动到 ear 根目录并在其清单类路径中引用 MyTestApp.jar

Deployment of multiple, depended CDI jars in one EAR

【讨论】:

  • 我有点困惑的一点是,为什么在MyFramework.jar 中定义的 CDI 扩展能够扫描其类加载器之外的 bean(即MyTestApp.jar),但一个普通的 CDI 托管 bean 在MyFramework.jar 无法在其类加载器之外注入 bean(即 MyTestApp.jar)。任何想法为什么?
  • 不,我对 CDI 不够熟悉,无法理解内部扩展机制,我想由于它旨在与第三方技术交互,因此它可能会使用层次结构中更高的类加载器来了解系统中的所有组件。
【解决方案2】:

在我看来,让您的“框架”依赖于您的应用程序实现可能是一个糟糕的架构决策。也许应该是您的应用程序实现了一些框架级接口来实现您的目标。当您拥有它或希望它工作时,表明您耳朵中的应用程序(实际上是任何应用程序)可以通过为框架提供实现来影响您耳朵中所有其他应用程序的操作。这对我来说似乎是个坏主意。而且,如果您能够完成这项工作,并且您耳中的不止一个应用程序提供了此实现,那么 CDI 可能仍然会因为不明确的依赖关系而失败。

您可能可以使用一些特定于容器的依赖配置。例如,WildFly 允许您配置模块到模块的依赖关系。我认为,在 WildFly 中,一只耳朵可能会依赖战争。

虽然上述方法可能有效,但在考虑之后,我认为这也是一个坏主意。你真的应该认真看看你真正想要做什么。我认为,如果您更仔细地查看您正在尝试做的事情,您会发现您可能能够剥离或抽象一些依赖项,并且仍然为框架提供实现,但不是来自耳中的应用程序。

【讨论】:

    猜你喜欢
    • 2015-08-06
    • 1970-01-01
    • 2013-09-01
    • 2011-10-16
    • 2015-04-20
    • 2012-04-12
    • 2012-09-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多