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

Zec*_*eck 70 java rest ejb jax-rs java-ee

我正在尝试通过注释将无状态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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

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

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

你们能展示一些有用的例子吗?

Pas*_*ent 112

我不确定这应该有效.所以要么:

选项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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

选项2:使BookResource成为EJB

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

    @EJB
    private BookEJB bookEJB;

    //...
}
Run Code Online (Sandbox Code Playgroud)

看到:

选项3:使用CDI

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

    @Inject
    private BookEJB bookEJB;

    //...
}
Run Code Online (Sandbox Code Playgroud)

看到:

  • "我不确定这应该有效." - 为什么?我希望你可以在没有玩一堆游戏的情况下注入EJB (2认同)

Mic*_*ons 14

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

只需通过类级别的@ 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>
Run Code Online (Sandbox Code Playgroud)

如果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项目进行测试.

快乐的编码.


Mar*_*tin 10

您应该能够在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;
  }
}
Run Code Online (Sandbox Code Playgroud)

通过此设置,您可以让JAX-RS根据请求为您实例化BookResource,并注入所有必需的依赖项.如果您将BookResource类设置为单例 JAX-RS资源,那么您可以将其放入getSingletons

public Set<Object> getSingletons() {
  singletons.add(new BookResource());
  return singletons;
}
Run Code Online (Sandbox Code Playgroud)

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


LeC*_*Che 5

不幸的是,我的回答太长,无法发表评论,所以这里就是这样.:)

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

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

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

  • 人们经常谈论 EJB 的“开销”,好像它们是重量级的一个公认的事实,但大多数开发人员从来没有费心去衡量它。Adam Bien 在 2008 年表明 EJB 和 POJO 之间的性能差异很小(&lt; 10%)(http://www.adam-bien.com/roller/abien/entry/is_it_worth_using_pojos),从那时起性能才有所提高。简而言之,如果您试图通过比较 POJO 和 EJB 来优化应用程序的性能,那么您找错了地方。 (2认同)