将EJB注入JAX-RS(RESTful服务)

我试图通过注释将无状态EJB注入我的JAX-RS web服务。 不幸的是,EJB是null ,当我尝试使用它时,我得到一个NullPointerException

 @Path("book") public class BookResource { @EJB private BookEJB bookEJB; public BookResource() { } @GET @Produces("application/xml") @Path("/{bookId}") public Book getBookById(@PathParam("bookId") Integer id) { return bookEJB.findById(id); } } 

我究竟做错了什么?

以下是关于我的机器的一些信息:

  • Glassfish 3.1
  • Netbeans 6.9 RC 2
  • Java EE 6

你们可以举个实例吗?

我不确定这应该工作。 所以:

选项1:使用注入提供者SPI

实现一个将执行查找并注入EJB的提供程序。 看到:

  • @EJB注射 。

com.sun.jersey的示例:jersey-server:1.17:

 import com.sun.jersey.core.spi.component.ComponentContext; import com.sun.jersey.core.spi.component.ComponentScope; import com.sun.jersey.spi.inject.Injectable; import com.sun.jersey.spi.inject.InjectableProvider; import javax.ejb.EJB; import javax.naming.Context; import javax.naming.InitialContext; import javax.ws.rs.ext.Provider; import java.lang.reflect.Type; /** * JAX-RS EJB Injection provider. */ @Provider public class EJBProvider implements InjectableProvider<EJB, Type> { public ComponentScope getScope() { return ComponentScope.Singleton; } public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) { if (!(t instanceof Class)) return null; try { Class c = (Class)t; Context ic = new InitialContext(); final Object o = ic.lookup(c.getName()); return new Injectable<Object>() { public Object getValue() { return o; } }; } catch (Exception e) { e.printStackTrace(); return null; } } } 

选项2:使BookResource成为一个EJB

 @Stateless @Path("book") public class BookResource { @EJB private BookEJB bookEJB; //... } 

看到:

  • 如何将REST服务与EJB 3.1结合起来
  • EJB 3.1和REST – 轻量级混合

选项3:使用CDI

 @Path("book") @RequestScoped public class BookResource { @Inject private BookEJB bookEJB; //... } 

看到:

  • 将jar中的EJB注入战争中的jax-rs类

这个线程是相当老,但我昨天打了同样的问题。 这是我的解决scheme:

只需在类级别通过@ javax.annotation.ManagedBean使BookResource成为托pipebean。

为了这个工作,你需要启用一个beans.xml的CDI:

 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> </beans> 

如果BookResource是war文件的一部分,则该文件需要位于WEB-INF中。 如果BookResource与ejbs一起打包放入META-INF。

如果你想使用@EJB,你就完成了。 如果要通过@Inject注入EJB,则必须将beans.xml放入ejbs jar文件中,并放入META-INF中。

你在做什么:你只是告诉容器,资源应该被容器pipe理。 因此,它支持注入以及生命周期事件。 所以你有你的商业门面,而不是将其推广到EJB。

您不需要扩展javax.ws.rs.core.Application就可以工作。 BookResource作为根资源自动请求作用域。

testing了Glassfish 3.1.2和一个maven项目。

快乐的编码。

您将能够在JAX-RS资源中进行注入,而无需使用EJB或CDI组件。 但是你必须记住你的JAX-RS资源不能是单身人士。

所以,你用这个代码设置你的应用程序。 这使得BookResource每个请求的 JAX-RS资源。

 @javax.ws.rs.ApplicationPath("application") public class InjectionApplication extends javax.ws.rs.core.Application { private Set<Object> singletons = new HashSet<Object>(); private Set<Class<?>> classes = new HashSet<Class<?>>(); public InjectionApplication() { // no instance is created, just class is listed classes.add(BookResource.class); } @Override public Set<Class<?>> getClasses() { return classes; } @Override public Set<Object> getSingletons() { return singletons; } } 

通过这个设置,您可以让JAX-RS为每个请求实例化BookResource并注入所有必需的依赖关系。 如果你制作BookResource类的单例 JAX-RS资源,这是,你把getSingletons

 public Set<Object> getSingletons() { singletons.add(new BookResource()); return singletons; } 

然后,您创build了不由JAX-RS运行时pipe理的实例,并且容器中没有人关心注入任何东西。

不幸的是,我的回答太长了,所以在这里。 🙂

Zeck,我希望您能够像Pascal所build议的那样,通过将您的bean推广到EJB来知道您到底在做些什么。 不幸的是,像现在Java EE一样,“将一个类作为一个EJB”非常容易,您应该意识到这样做的含义。 每个EJB都会创build额外的function以及它提供的额外function:它们是事务感知的,拥有自己的上下文,参与完整的EJB生命周期等。

我认为你应该做一个干净的和可重用的方法是:提取访问您的服务器服务(希望通过SessionFacade :)访问到BusinessDelegate 。 这个委托应该使用某种types的JNDI查找(可能是ServiceLocator – 是的,它们在Java EE中仍然有效)来访问您的后端。

好吧,如果你真的真的需要注入,因为你不想手动编写JNDI访问,你仍然可以让你的委托成为一个EJB,虽然它……只是感觉错了。 :)这样,如果你决定切换到JNDI查找方法,至less可以很容易地用其他东西replace它。

我试图做同样的事情。 我正在使用EJB 3.1,并将我的应用程序部署为具有单独的EJB项目的EAR。 正如Jav_Rock指出的,我使用上下文查找。

 @Path("book") public class BookResource { @EJB BookEJB bookEJB; public BookResource() { try { String lookupName = "java:global/my_app/my_ejb_module/BookEJB"; bookEJB = (BookEJB) InitialContext.doLookup(lookupName); } catch (NamingException e) { e.printStackTrace(); } } @GET @Produces("application/xml") @Path("/{bookId}") public Book getBookById(@PathParam("bookId") Integer id) { return bookEJB.findById(id); } } 

查看下面的链接,了解非常有用的JNDI查找技巧

JNDI查找技巧

阿尔詹是对的。 我创build了另一个类来初始化EJB,而不是为RS创build一个bean

 @Singleton @LocalBean public class Mediator { @EJB DatabaseInterface databaseFacade; 

避免空指针与:

 @Path("stock") public class StockResource { @EJB DatabaseInterface databaseFacade; ... 

它实际上在GF上工作

我有同样的问题,我解决了它通过上下文查找调用EJB(注入是不可能的,我有相同的错误NullPointerException)。