繁体   English   中英

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

[英]Inject an EJB into JAX-RS (RESTful service)

我正在尝试通过注释将无状态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的提供程序。 看到:

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;

    //...
}

看到:

选项3:使用CDI

@Path("book")
@RequestScoped
public class BookResource {

    @Inject
    private BookEJB bookEJB;

    //...
}

看到:

这个线程相当陈旧,不过我昨天也遇到了同样的问题。 这是我的解决方案:

只需通过类级别的@ javax.annotation.ManagedBean将BookResource设置为托管bean。

为此,您需要使用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中。

你在做什么:你只是告诉容器资源应该是容器管理的。 因此,它支持注入和生命周期事件。 因此,您拥有业务外观,而无需将其提升为EJB。

您无需为此扩展javax.ws.rs.core.Application。 BookResource作为根资源自动请求作用域。

使用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;
}

然后,您创建了一个不受JAX-RS运行时管理的实例,并且容器中没有人关心注入任何内容。

不幸的是,我的回答太长了,无法发表评论,所以这里有。 :)

Zeck,我希望你通过将你的bean推广到EJB来了解你正在做什么,正如Pascal所建议的那样。 不幸的是,就像现在使用Java EE“将类创建为EJB”一样简单,您应该意识到这样做的含义。 每个EJB都会产生开销以及它提供的附加功能:它们具有事务感知能力,具有自己的上下文,它们参与完整的EJB生命周期等。

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

好的,关闭记录:如果你真的,真的, 真的需要注入,因为你不想手动编写JNDI访问,你仍然可以让你的委托成为EJB,虽然它......好吧,它只是感觉不对。 :)至少如果您决定切换到JNDI查找方法,至少可以很容易地用其他东西替换它...

我试图做同样的事情。 我正在使用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查找提示

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

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

避免空指针:

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

它实际上适用于GF

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM