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

Java 将@EJB注入显式创建的对象->;空指针异常,java,jakarta-ee,nullpointerexception,ejb,glassfish-4.1,Java,Jakarta Ee,Nullpointerexception,Ejb,Glassfish 4.1,我试图弄清楚对象实例化在JavaEE中是如何工作的。我注意到,如果定义成员的类是由我而不是容器显式实例化的,那么如果我试图访问一个应该通过@EJB注入的成员,就会得到一个NullPointerException。我的结论是,即使bean被标记为被管理,如果不让容器实例化它,它也不会被管理。我们可以让容器管理这些对象吗 假设我们有以下设置,是否可以在ClassC中实例化(显式地)ClassB并让ClassB从ClassA调用方法而不引发NullPointerException @Stateless

我试图弄清楚对象实例化在JavaEE中是如何工作的。我注意到,如果定义成员的类是由我而不是容器显式实例化的,那么如果我试图访问一个应该通过@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(); 
    }
}

我之所以关注它,是因为我在相当于类A的环境中需要使用EntityManager来持久化一些数据,同时我的类B实际上是一个接口,所以我需要能够在运行时决定在类C中实例化哪个实现。也许还有其他方法可以做到这一点?

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

Context initialContext = new InitialContext();
ClassB b = (ClassB)initialContext.lookup("java:global/yourappname/ClassB!com.package.containing.ClassB");
因此,您可以使用您需要的任何逻辑来确定您需要的实际ClassB实现的JNDI名称,然后进行查找

Context initialContext = new InitialContext();
ClassB b = (ClassB)initialContext.lookup("java:global/yourappname/ClassB!com.package.containing.ClassB");
我注意到,如果定义成员的类是由我而不是容器显式实例化的,那么如果我试图访问一个应该通过@EJB注入的成员,就会得到一个NullPointerException

这是显而易见的,因为依赖项是由容器注入的。因此,如果您正在创建实例,并且没有为依赖项设置任何值,那么依赖项将为
null
。另一方面,当容器创建实例时,它还设置其依赖项的值

我的结论是,即使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(); 
    }
}
否,创建实例时,依赖项将为null

我之所以研究它,是因为我在我的,相当于,类A中需要使用EntityManager来持久化一些数据,同时我的类B实际上是一个接口,所以我需要能够在运行时决定在类C中实例化哪个实现。也许还有其他方法可以做到这一点

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

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

@EJB(beanName="SpecificService")
private Service specificService;
请参阅此链接:


或者,如果您正在使用,您可以使用

您不能用“new”关键字实例化Ejb,这不是一个选项。要引用ejb类,您可以进行容器注入,也可以通过JNDI进行查找。每一个选择都有它的意义,这是你根据上下文使用的方法还是其他方法。这很好,我绝对会尝试一下,并阅读一下我相信的JNDI!我还发现了一个类似的问题。您是否愿意评论一下这两种方法之间的差异。也就是说,使用JNDI与\@singleston\@startup“producer class”相比,我应该考虑什么?JNDI查找是访问EJB、数据源等的“老式”方式。一般来说,这是一种PITA,因为您必须正确处理异常和类型转换结果。如果没有使用容器注入的选项(在Java EE 7运行时中几乎从来没有),那么您只会使用JNDI。如果我将一个类注释为EJB,但不在任何地方注入它,并在JPQL for DTO Projection(Hibernate)中实例化它,那么类容器是托管bean吗?如果您注入bean,它将是容器托管的。如果您使用new关键字实例化它,它将不是容器管理的。