将@EJB注入显式创建的对象 - >空指针异常

时间:2017-01-07 03:45:10

标签: java java-ee nullpointerexception ejb glassfish-4.1

我试图找出对象实例化在Java EE中的工作原理。我注意到如果我尝试访问一个应该通过@EJB注入的成员,如果定义成员的类已由我而不是容器显式实例化,我会注意到我得到一个NullPointerException。我的结论是,即使bean被标记为要管理,如果没有让容器实例化它也不是。我们可以让容器管理这样的对象吗?

假设我们有以下设置,是否可以在ClassC中实例化(显式)ClassB并让ClassB从ClassA调用一个方法而不抛出NullPointerException?

@Stateless
public class ClassA {
    public void bar() {
        // Does something fun
    }
}

@Stateless 
public class ClassB {
    @EJB
    private ClassA A;

    public void foo() {
        A.bar(); // throws NullPointerException if ClassB 
                 // is explicitly instantiated works fine
                 // if injected with @EJB
    }
}

public class ClassC {
  //@EJB // Only way to go? Can we choose an implementation of ClassB?
    private ClassB B;

    public ClassC() {
        this.B = new ClassB(); // Bad idea? Possible??
        this.B.foo(); 
    }
}

我正在研究它的原因是因为我在我的,相当于,ClassA需要使用EntityManager来保存一些数据,同时我的ClassB实际上是一个接口所以我需要能够决定在运行时哪个实现在ClassC中实例化。也许有其他方法可以做到这一点?

2 个答案:

答案 0 :(得分:1)

  

我注意到,如果我尝试访问一个应该通过@EJB注入的成员,如果定义成员的Class已经由我而不是容器显式实例化,那么我会得到一个NullPointerException。

这很明显,因为容器会注入依赖项。因此,如果您要创建实例而不为依赖项设置任何值,那么依赖项将为null。另一方面,当容器创建实例时,它还会设置其依赖项的值。

  

我的结论是,即使一个bean被标记为要管理,如果没有让容器实例化它也不是。

是的,这是正确的。因此,在创建实例时,实例将不受管理。

  

让我们说我们有以下设置,是否可以在ClassC中实例化(显式)ClassB并让ClassB从ClassA调用一个方法而不抛出NullPointerException?

不,当您创建实例时,依赖项将为null。

  

我调查它的原因是因为我在我的,相当于,ClassA需要使用EntityManager来保存一些数据,同时我的ClassB实际上是一个接口所以我需要能够在运行时决定在ClassC中实例化哪个实现。也许有其他方法可以做到这一点?

如果需要注入特定的实现,可以通过指定bean名称来实现。

@EJB(beanName="DefaultService")
private Service defautService;

@EJB(beanName="SpecificService")
private Service specificService;

请参阅此链接:http://www.adam-bien.com/roller/abien/entry/injecting_different_implementations_into_an

或者,如果您正在使用CDI,则可以使用@Qualifier

答案 1 :(得分:0)

如果不能使用注入,获取EJB引用的另一种方法是使用JNDI进行查找。

Context initialContext = new InitialContext();
ClassB b = (ClassB)initialContext.lookup("java:global/yourappname/ClassB!com.package.containing.ClassB");

因此,您可以使用所需的任何逻辑来确定所需的实际ClassB实现的JNDI名称,然后查找它。