【问题标题】:NPE injecting Singleton bean into a Singleton beanNPE 将 Singleton bean 注入 Singleton bean
【发布时间】:2017-11-29 02:41:05
【问题描述】:

我遇到了一个奇怪的问题,当将一个单例 bean(B 类)注入另一个单例 bean(A 类)时,我得到了一个 NullPointerException,其中两个 bean 都使用 EJB 3.1 注释。 NPE 发生是因为从类 A 访问时映射为空,即使注入了类 B。 例如:

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.inject.Inject;

@Singleton
@Startup
public class A {
    @Inject
    B b;

    @PostConstruct
    public void initialise() {
        b.map.put("test", 1);
        System.out.println("A initialised");
    }
}
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import java.util.HashMap;

@Singleton
public class B {
    HashMap<String, Integer> map;

    @PostConstruct
    public void initialise() {
        map = new HashMap<>();
        System.out.println("B initialised");
    }
}

但是,如果我对 B 类使用 CDI 单例注释,则代码将按预期执行:

import javax.annotation.PostConstruct;
import javax.inject.Singleton;
import java.util.HashMap;

@Singleton
public class B {
    HashMap<String, Integer> map;

    @PostConstruct
    public void initialise() {
        map = new HashMap<>();
        System.out.println("B initialised");
    }
}

EJB 注解在这种情况下不起作用是有原因的吗?

【问题讨论】:

  • 尝试对 B 类使用渴望初始化 - 例如使用@Startup。这样我怀疑 B 可能还没有被初始化(你只得到某种代理对象)并且你尝试访问它的方式太快了。
  • 刚刚再次尝试@Startup 以确定但仍然抛出 NPE。甚至在 A 中尝试过 @DependsOn("B") ,但也没有用。

标签: jakarta-ee dependency-injection ejb cdi


【解决方案1】:

@EJB 和@Inject 之间存在区别。 不幸的是,CDI 和 EJB 注释很相似,但可能工作方式不同!

在您的情况下,如果 Bean B 是 CDI Bean(使用 CDI Singleton 注释进行注释),则 Bean B 是正确注入 CDI 的

如果您使用 @EJB 而不是 @Inject,我会假设 EJB 注入将起作用 - 如果 Bean B 使用 javax.ejb.Singleton 进行注释。

【讨论】:

    【解决方案2】:

    许多人没有意识到的一个重要事实是,EJB 客户端只能看到 EJB 的 公共方法的“视图”,无论它被注入到哪里。

    您正试图直接访问其中一个实例变量:

        b.map.put("test", 1);
    

    如果给 EJB 增加一个委托方法B

    public Integer put(String key, Integer value) {
        return map.put(key, value);
    }
    

    并调用它:

    @PostConstruct
    public void initialise() {
        b.put("test", 1);
        System.out.println("A initialised");
    }
    

    你会得到

    20:18:16,823 INFO [stdout] (ServerService 线程池 -- 70) B 已初始化
    20:18:16,824 INFO [stdout] (ServerService 线程池 -- 70) 已初始化

    正如预期的那样。

    有关详细信息,请参阅 EJB 规范的第 3 节。在这里你会找到声明:

    容器对客户端透明地为会话对象提供安全、并发、事务、交换到二级存储和其他服务。

    如果您要成功地直接访问实例变量,那么您将绕过所有这些。

    【讨论】:

      猜你喜欢
      • 2014-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-20
      相关资源
      最近更新 更多