【问题标题】:CDI and Resource Injection with JAX-RS and Glassfish使用 JAX-RS 和 Glassfish 进行 CDI 和资源注入
【发布时间】:2015-12-16 01:52:24
【问题描述】:

我目前正在开发一个 JAX-RS Servlet,然后我想将其部署在 Glassfish 4.1 服务器中(因此 JAX-RS 运行时是 Jersey 2.x)。

我不想使用 Spring 来进行配置和 DI 的东西,而是想尝试 Java EE 的方式来做这件事。但是,CDI 和我在 Glassfish 服务器中配置的数据源的注入都不起作用。但首先这里是关于 servlet 的相关内容。

依赖项(在父 pom 中使用版本和范围声明 - 这不是您在此处看到的):

<dependencies>
    <!-- Java EE API -->
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
    </dependency>

    <!-- Jersey CDI support -->
    <dependency>
        <groupId>org.glassfish.jersey.ext.cdi</groupId>
        <artifactId>jersey-cdi1x</artifactId>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.ext.cdi</groupId>
        <artifactId>jersey-cdi1x-ban-custom-hk2-binding</artifactId>
    </dependency>

    <!-- Logging dependencies -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
    </dependency>
</dependencies>

web.xml:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1">

<servlet>
    <servlet-name>Backend</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>

    <!-- Disable Moxy JSON -->
    <init-param>
        <param-name>jersey.config.disableMoxyJson</param-name>
        <param-value>true</param-value>
    </init-param>

    <!-- Register resource classes -->
    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>org.test.Service</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>Backend</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

</web-app>

beans.xml:

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
   version="1.1" bean-discovery-mode="all">
</beans>

Service.java:

@Path("/")
@RequestScoped
public class Service {

    @Inject
    private DataProvider dataProvider;

    @Path("test")
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public Response test(){
        return Response.ok(dataProvider.getArticles()).build();
    }

}

SQLDataProvider.java:

@Default
@ApplicationScoped
@Singleton
@Path("singleton-bean")
public class SQLDataProvider implements DataProvider {

    @Resource(name = "jdbc/db_1")
    private DataSource dataSource;

    private SQLQueryFactory factory;

    @Override
    public List<Article> getArticles() {
        if(factory == null){
            factory = new SQLQueryFactory(new Configuration(new MySQLTemplates()), dataSource);
        }

        QArtikel artikel = QArtikel.artikel;
        List<String> names = factory.select(artikel.artikeltyp).from(artikel).fetch();

        return names.stream().map(Article::new).collect(Collectors.toList());
    }
}

如果我在 Glassfish 服务器中部署此 servlet 并执行请求,则会引发以下异常:

javax.servlet.ServletException: A MultiException has 3 exceptions.  They are:
    1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=DataProvider,parent=SkiBazaarService,qualifiers={},position=-1,optional=false,self=false,unqualified=null,158365417)
    2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of org.skiclub.service.SkiBazaarService errors were found
    3. java.lang.IllegalStateException: Unable to perform operation: resolve on org.skiclub.service.SkiBazaarService

如您所见,我已经尝试了来自this post 的用户 G. Demecki 的解决方案,方法是在我的 servlet 中包含两个 Jersey 依赖项 - 但没有成功。我还尝试了来自 Oracle 的 solution,它发布在 this post 的某个地方。但这对我也不起作用。

我还看到了一个解决方案,您可以在 this post 中为 HK2 运行时指定从类型到实例的绑定。我承认我没有尝试过,因为我认为必须以编程方式注册要注入的实例,这完全是 DI 背后的想法。

但还有另一个问题。如果我将Service类中DataProvider的声明修改为如下

private DataProvider dataProvider = new SQLDataProvider();

CDI 的问题消失了,但抛出了 NPE,因为我试图从 JNDI 获取的 DataSource 没有注入到 SQLDataProvider 的实例中。因此,Java EE 的资源注入似乎在 JAX-RS Container 中也不起作用。对于这个问题,我在研究过程中没有找到任何可能的解决方案。

我希望有人可以告诉我我需要在配置中进行哪些更改才能使 CDI 和资源注入与 JAX-RS 一起使用,因为目前这对我来说似乎是不可能的。

亲切的问候 帕斯卡

【问题讨论】:

  • 实际上在 JNDI 中是 jdbc/db_1。我假设您在 GlassFish 上设置了 DataSource。您是否通过 GlassFish JNDI 浏览器验证了这是正确的 JNDI 地址?我对@Path 注释SQLDataProvider 有点困惑。另外,@ApplicationScoped@Singleton 似乎有点多余。
  • 是的,DataSource 在该名称下可用。我刚刚在 JDBC 资源下的管理控制台中检查了它。在相应的列表中出现了我的 DataSource,它指出它在 JNDI 名称 jdbc/db_1 下可用。我还使用“asadmin list-jndi-entries --context jdbc”命令对其进行了检查。 @Path 注解来自 Oracle 在此链接下发布的解决方案 docs.oracle.com/javaee/7/tutorial/jaxrs-advanced004.htm

标签: java jakarta-ee glassfish jax-rs cdi


【解决方案1】:

看到这个问题:

Recource injection doesn't work with glassfish 4 while lookup works

按照上述问题的建议,尝试查找您的 Resource 其他属性,例如 mappedName

 @Resource(mappedName = "jdbc/db_1")
 private DataSource dataSource;

【讨论】:

  • 感谢您的提示!但是,它似乎不适用于我的注释(当我显式打开上下文并加载数据源时它工作正常 - 但我仍然希望使用注释让它工作)......目前我认为来自 Jersey 的 ServletContainer 绝对把事情搞砸了,但我很乐意让这个主题的专家纠正我并告诉我它不起作用的真正原因
  • 那么你为什么要使用 Jersey ServletContainer 甚至包括 Jersey 1.x。 GlassFish 4.* 随 Jersey 2 提供。请参阅 docs.oracle.com/javaee/7/tutorial/jaxrs002.htm#GILIK 第 29.2.7 节
  • 我没有使用 Jersey 1.x 的东西。 ServletContainer 仍包含在 Jersey 2.x 中,您可以在此处看到 jersey.java.net/apidocs/2.11/jersey/org/glassfish/jersey/…
  • 关于 Servlet Container 的使用:Container 只是一个符合 Servlet 2+ 的方式,用于在 web.xml (jersey.java.net/documentation/latest/…) 中连接 Jersey。我这样做是因为如果我还可以在 web.xml 文件中指定我的资源类,我不想创建一个 Application 子类
  • 很公平。您是否尝试过坚持使用 Java EE API 并使用它来引导您的 REST 应用程序:&lt;servlet-mapping&gt; &lt;servlet-name&gt;javax.ws.rs.core.Application&lt;/servlet-name&gt; &lt;url-pattern&gt;/*&lt;/url-pattern&gt; &lt;/servlet-mapping&gt;
猜你喜欢
  • 2015-05-05
  • 2019-03-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-07
  • 2012-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多