简体   繁体   English

如何注入另一个类加载器中存在的CDI托管bean

[英]How to inject a CDI managed bean that exists in another classloader

I am working on a framework which will be used in Java EE applications and therefore is likely to be deployed in the \\lib directory of an EAR file. 我正在研究一个将在Java EE应用程序中使用的框架,因此很可能部署在EAR文件的\\lib目录中。

The framework will use CDI to programmatically lookup and inject beans that are located in the Java EE application that is using the framework. 该框架将使用CDI以编程方式查找和注入位于使用该框架的Java EE应用程序中的bean。 The problem I've got is when the Provider.get() method from javax.enterprise.Provider<T> is called by my framework to get an instance of the bean, Weld throws a UnsatisfiedResolutionException . 我遇到的问题是,当我的框架调用javax.enterprise.Provider<T>Provider.get()方法来获取bean的实例时,Weld抛出UnsatisfiedResolutionException

To check this isn't an issue related to CDI I've also tried using MyClass myClass = Class.forName(clazz).newInstance(); 要检查这不是与CDI相关的问题,我也尝试过使用MyClass myClass = Class.forName(clazz).newInstance(); to get an instance of the class but a ClassNotFoundException is thrown. 获取该类的实例,但抛出ClassNotFoundException

The structure of EAR file I'm using for testing purposes is as follows: 我用于测试目的的EAR文件的结构如下:

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

My test application's EAR contains an application.xml file which includes <library-directory>lib</library-directory> . 我的测试应用程序的EAR包含一个application.xml文件,其中包含<library-directory>lib</library-directory>

I believe this problem is occurring because the bean I want to inject exists in a separate classloader. 我相信发生此问题是因为我要注入的bean存在于单独的类加载器中。 ie \\lib\\MyFramework.jar is in a different classloader to MyTestApp.jar . \\lib\\MyFramework.jarMyTestApp.jar位于不同的类加载器中。 I found this SO question which seems to suggest this is the case. 我发现了这个SO问题 ,似乎暗示情况确实如此。 Given that I'm developing a framework I don't believe the answer in the question is a viable solution for my needs. 鉴于我正在开发一个框架,所以我认为问题的答案不能满足我的需求。

I'm intrigued to find out whether creating a CDI portable extension would allow me to get an instance of the bean I want to use, but don't have enough experience in this area. 我很想知道创建CDI可移植扩展是否可以让我获得要使用的bean的实例,但是在这一领域没有足够的经验。 Using @Observes ProcessAnnotatedType<T> I can see beans that exist outside of the \\lib directory in an EAR file, including the ones I want to programmatically inject. 使用@Observes ProcessAnnotatedType<T>我可以看到EAR文件中\\lib目录之外的bean,包括我要以编程方式注入的bean。

My questions are: 我的问题是:

  1. Am I correct in assuming this problem is occurring because \\lib\\MyFramework.jar and MyTestApp.jar are in separate classloaders? 我是否可以假设由于\\lib\\MyFramework.jarMyTestApp.jar位于单独的类加载器中而发生此问题?

  2. Is there anything I can do using CDI that will allow my framework when deployed in the \\lib directory of an EAR file to make the Provider.get() method call to avoid Weld throwing a UnsatisfiedResolutionException ? 使用CDI,我可以做些什么来使我的框架在EAR文件的\\lib目录中部署时进行Provider.get()方法调用,以避免Weld抛出UnsatisfiedResolutionException吗?

  3. Is there anything I can do outside of CDI to achieve same result? 在CDI之外我还能做些什么来达到相同的结果?


Update 更新

I've now tried moving MyFramework.jar to the root of the EAR file and also including the jar module in the application.xml file but the container fails to start the application due to a CDI unsatisfied dependency exception. 我现在尝试将MyFramework.jar移到EAR文件的根目录,并且还将jar模块包含在application.xml文件中,但是由于CDI不满意的依赖项异常,容器无法启动应用程序。 The bean referenced in the exception can be injected when MyFramework.jar is located in the \\lib directory and is a different bean to the one referenced in my question. MyFramework.jar位于\\lib目录中并且与我的问题中引用的bean不同时,可以注入异常中引用的bean。

1 : yes 1:是的

2 : actually I don't know 2:实际上我不知道

3 : Yes, you must understand the ear classloader hierarchy, the jars in ear lib directory are loaded at the ear level and so available in all child classloaders (there is one child classloader per component in the ear). 3:是的,您必须了解ear类加载器的层次结构,ear lib目录中的jar是在ear级别加载的,因此在所有子类加载器中都可用(ear中每个组件有一个子类加载器)。

It means that MyFramework.jar is visible from MyTestApp.jar ear child classloader but the inverse is false. 这意味着MyFramework.jar从MyTestApp.jar可以从子类加载器中看到,但相反是false。

see In java EE, which jars should I put in the library dir? 请参见在Java EE中,应该在库目录中放入哪个jar?

You can either : 您可以:

  • move MyTestApp.jar to ear lib directory (MyFramework.jar can be either in lib dir and reference MyTestApp.jar or at ear root) 将MyTestApp.jar移到ear lib目录(MyFramework.jar可以在lib目录中,引用MyTestApp.jar或在ear根目录)
  • move MyFramework.jar at ear root and reference MyTestApp.jar in its manifest classpath 在耳朵根部移动MyFramework.jar并在其清单类路径中引用MyTestApp.jar

see Deployment of multiple, depended CDI jars in one EAR 请参阅在一个EAR中部署多个依赖的CDI jar

It seems to me that it might be a poor architectural decision to have your "framework" depend on your application implementation. 在我看来,使“框架”取决于应用程序的实现可能是一个糟糕的体系结构决定。 Perhaps it should be that your application that implements some framework-level interface to achieve your goal. 也许应该是您的应用程序实现了一些框架级的接口来实现您的目标。 As you have it, or would like it to work, suggests that an application, any application really, in your ear could influence the operation of all other applications in your ear by providing implementation to the framework. 当您拥有或希望它运行时,它建议通过提供对框架的实现,您耳中的应用程序(实际上是任何应用程序)都可能影响您耳中所有其他应用程序的操作。 This seems like a bad idea to me. 对我来说,这似乎是个坏主意。 And if you were able to make this work and more that one application in your ear provided this implementation, CDI may still fail because of ambiguous dependencies. 而且,如果您能够完成这项工作,并且提供了一个以上的应用程序,那么CDI可能仍然会由于不确定的依赖性而失败。

There may be some container specific dependency configurations that you might be able employ. 您可能可以使用一些特定于容器的依赖项配置。 WildFly, for example, allows you to configure module-to-module dependencies. 例如,WildFly允许您配置模块到模块的依存关系。 I think, it might be possible, in WildFly, for an ear to depend on a war. 我认为,在WildFly中,耳朵可能依赖战争。

While the above might work, after thinking about it, I this it is also a bad idea. 尽管上面的方法可能会起作用,但经过深思熟虑,我认为这也不是一个好主意。 You should really take a hard look at what you are really trying to do. 您应该认真研究一下您真正想做什么。 I think if you take a harder look at what you are trying to do, you will discover that your will probably be able to peal out or abstract some dependencies and still provide implementation to the framework, but not from the applications in the ear. 我认为,如果您更加认真地考虑要执行的操作,您会发现您可能能够消除或抽象一些依赖关系,并且仍然可以为框架提供实现,但不能从耳边的应用程序中获得。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM