有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

@Singleton类的@Inject字段上的java NPE

我遇到了一个奇怪的场景,在这个场景中,无论我尝试了什么解决方案,使用CDI管理单例的任何尝试都会导致失败,我甚至不确定这是否是可行的/可以做到的,因此我在这里发布的原因

我将尽力解释当前的场景,我想知道我的意图是否可以实现,如果可以,通过什么方式实现,如果没有,除了“升级”该jar中的单例实例,还有其他选择吗。如果我遗漏了代码的细节/部分,请让我知道,因为这有点不寻常,如果我提供了所需的一切,我不知道

背景

  • JBoss 7.2 EAP用作服务器
  • 在一个大型Maven项目中,父pom文件仅充当pom,以在Maven中为所有其他子项目提供依赖项/配置,这些子项目主要为ejb/ear/war
  • JBoss中使用的自定义模块为一些项目提供了许多依赖项,所以它只是一个装满jar文件的文件夹,包括在其他项目中使用的自定义jar
  • 测试目的是耳朵。ear部署到服务器,其中包含一个测试ejb测试war项目
  • war项目提供了一个对自定义模块中的一个jar文件的依赖关系(jar实际上只是主项目的另一个子项目),在编译和运行时,它可以解决问题,没有问题(在我看来,与使用maven依赖关系完全相同)
  • 到目前为止,war项目通过getInstance()方法从jar调用单例实例(纯粹作为业务逻辑),一切正常

意图

  • 从jar中删除singleton类的所有私有构造函数/getInstance(),并用@singleton注释它们,希望通过使用@Inject而不是使用getInstance()方法,将war项目中的所有调用改为另一种方式

采取的步骤

  • 对于一个单独的类,删除了私有构造函数getInstance(),为该类创建了一个新接口,以仅公开某些方法,而singleton类正在实现新接口,并使用来自javax的@singleton注释进行标记。注入

  • 在war项目中,删除了getInstance()调用,并将使用@Inject的变量设置为使用它的类中的字段,如下所示:

    @Inject
    private Management managementInterface;
    ...
    void someMethod(){
        managementInterface.performBusinessLogic();
    }
    
  • 这导致调用performSomeBusinessLogic()时抛出NPE,对此我找到了几个答案,因此我添加了一个bean。xml到具有发现模式=all的jar,尝试@Singletonjavax。ejb,但是没有任何东西能够使注入该单例成为可能

  • 我已经搜索了很长一段时间来了解如何做到这一点,但是这里/在google上描述的大多数场景都是关于部署在同一容器中的应用程序之间的ejb间通信,但这并不相同:我们正试图使用CDI从不是ejb/war项目的jar文件中注入一个单例,而是一个简单的java库

需要考虑的事项

  • 该singleton类以前在多个ejb/war项目中使用过,没有任何问题,因此它在JBoss中作为一个自定义模块和一个独立的jar,这意味着对于所有调用ejb/war项目,该类实际上只有一个实例,我们还避免了整个上下文/类加载的典型问题

  • 那singleton公开了相当多的方法,其中一些方法实际上最好不要公开,所以我想在它前面放一个接口,这样调用的客户机只能访问一些方法,但不能访问所有方法

  • 由于项目的结构和依赖项的管理方式,jar文件可以访问许多库/依赖项,因此其目的是放弃创建和使用单例的旧方法,并将其迁移到更现代的方式

  • IDE(Intellij)能够无问题地解决依赖关系,如以下附件中所示,单击蓝色标记图标,它将指向标记为@Singleton的类,该类正在实现该接口。 dependency being solved by the IDE

问题

  • 有没有可能将jar项目中的单例从传统方式更改为使用服务器CDI的方式?在这方面,使用注释是最好的,但是如果有其他可用的解决方案,我愿意接受它们

共 (1) 个答案

  1. # 1 楼答案

    如果管理类位于jar依赖项中(由JBoss提供或打包在ear中),则不会被视为CDIBean。 它必须包含一个EJB/CDI模块,该模块与测试EJB的级别相同

    另一种方法是使用@Remote EJB注释并将jar部署为库,而不是简单的依赖关系

    (对我来说)不清楚重构的目的,但如果是为了避免在每个需要的bean上手动实例化该类,您可以编写一个简单的生成器:

    @Singleton
    public class ManagementProvider() {
        @Produces
        public Management getInstance() {
            return Management.getInstance();
        }
    }
    

    然后你可以随时使用@Inject