将JAX-RS与CDI集成的正确方法?

时间:2017-05-17 15:05:51

标签: java rest java-ee jax-rs quartz-scheduler

我曾经在Jersey REST资源中集成Service和DAO bean,并在Java EE tutorial之后使用@Path注释它们

  

通常,要使JAX-RS使用企业bean,您需要使用@Path注释bean的类以将其转换为根资源类。您可以将@Path注释与无状态会话bean和单例POJO bean一起使用。

所以我的代码曾经是这样的:

@Path("/")
public class ServiceResource {
   @Inject
   private AccountService accountService;

   @GET
   @Path("/account/get")
   public Account getAccount(@QueryParam("id") String id) {
     return accountService.get(id);
   }
}

@javax.inject.Singleton
@Path("")
public class AccountService {
   public Account get(String id){...}
}

现在,我开始将Quartz Job集成到我的应用程序中,我想找到一种方法将AccountService注入到这样的工作中

public class AccountJob implements Job {
  @Inject
  private AccountService accountService;

  @Override
  public void execute(JobExecutionContext jec) throws JobExecutionException {
    accountService.updateAllAccounts();
  }
}

我发现这个answer告诉我使用DeltaSpike来执行Job,所以我将以下依赖项添加到pom.xml,并且不向任何类添加任何代码行accountService对我的Job的拒绝工作正常

<dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-scheduler-module-api</artifactId>
    <version>1.7.2</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-scheduler-module-impl</artifactId>
    <version>1.7.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.apache.deltaspike.cdictrl</groupId>
    <artifactId>deltaspike-cdictrl-api</artifactId>
    <version>1.7.2</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.apache.deltaspike.cdictrl</groupId>
    <artifactId>deltaspike-cdictrl-weld</artifactId>
    <version>1.7.2</version>
    <scope>runtime</scope>
</dependency>

但是,我意识到当我从@Path("")中移除AccountService时,其实例仍在ServiceResource内注入正常,所以我的问题如下:

  1. 为什么添加DeltaSpike依赖项可以在不使用@Path的情况下注入我的bean?
  2. 通过搜索更多内容,我了解DeltaSpike内部使用Weld进行注入,因为我已经在使用GlassFish 4.0,所以我知道Weld已经存在那么为什么注入在我的Job类和ServiceResource类中默认不起作用而不在我的bean上添加@Path?实际上为什么在Java教程中甚至会建议添加@Path
  3. 我的代码中是否有任何不良副作用,因为我认为我在这里混合使用多种DI方法,却没有真正理解它们是如何工作的?
  4. 更新:经过更多搜索,我发现Jersey没有使用Weld进行依赖注入,而是使用HK2,不同的框架也恰好是GlassFish的一部分,当我尝试在不使用AccountService的情况下注入@Path时,它会显示以下异常

      

    org.glassfish.hk2.api.UnsatisfiedDependencyException:SystemInjecteeImpl没有可用于注入的对象(r​​equiredType = AccountService ,parent = ServiceResource ,qualifiers = {}。 ..

    所以这会将问题更新为以下内容:

    1. 如何进行HK2注射? //不使用Java EE Tutorial中提到的@Path
    2. 如果我设法使用DI HK2,那么使用DeltaSpike对{Quartz Job}执行DI是否安全?是否可以将两个CDI framewroks混合在一起扫描类并进行注入?
    3. 我将我的源代码放在pastebin上; pom.xmlhereJavahere

3 个答案:

答案 0 :(得分:4)

您无需在this.countryServices = []; let data = [ {country: 'Spain', services: ['spainSservice1', 'spainService2']}, {country: 'Canada', services: ['canadaservice1', 'canadaservice2']}, ]; data.map(country => { this.countryServices.push(country.country); country.services.map(service => { this.countryServices.push(service); }) }); CDI bean上设置<select> <option *ngFor="let cs of countryServices" [ngValue]="cs">{{cs}}</option> </select> 注释。如果在您的应用程序上启用了CDI(在CDI 1.0中使用空beans.xml或在CDI&gt; 1.0中使用discovery-mode = all),则可以在{JAX-RS资源中Path任何CDI bean。 所以你只需要编写以下类:

AccountService

您在帖子中链接的文章涉及混合EJB和CDI注释。例如,您可以混合使用@Inject@Path("/") public class ServiceResource { @Inject private AccountService accountService; @GET @Path("/account/get") public Account getAccount(@QueryParam("id") String id) { return accountService.get(id); } } @javax.inject.Singleton public class AccountService { public void Account get(String id){...} } 注释。这很有趣,例如因为你可以:

  • 您的Rest资源中的EJB事务的好处(即使现在您可以使用@Stateless拦截器绑定)
  • 设置资源池

请注意,所有这些都可以在没有deltaspike依赖的帮助下工作。

对于第二个问题,由于Quartz管理自己的线程,因此CDI不会处理类,因此您无法在Quartz类中注入bean。 deltaspike模块的目的是允许在Quartz Jobs中注入CDI bean。在内部,deltaspike控制CDI上下文。

修改

关于你的上一个问题:

  • 您的HK2问题非常肯定来自缺少的依赖项(在您的应用程序或服务器中)。正如之前的评论中所述,我设法使用您提供的源文件在Glassfish 4(版本89)上部署您的应用程序。

  • 关于CDI与Quartz的集成,我认为最好是实现自己的@Path并使用@Transactional实现您的工作。请看一下这个链接:https://devsoap.com/injecting-cdi-managed-beans-into-quarz-jobs/

答案 1 :(得分:1)

首先注入的资源(bean)和Jersey Endpoint类(注入点)必须是CDI-Aware。必须由CDI检测。我们可以使用bean-discovery-mode =“all” - 然后CDI扫描所有类或 bean-discovery-mode =“annotated”并使用PROPER注释标记我们的类:从这里:Bean defining annotations。我更喜欢@Dependent或@RequestScoped

然后我们必须使用Jersey Extension

<dependency>
  <groupId>org.glassfish.jersey.ext.cdi</groupId>
  <artifactId>jersey-cdi1x-servlet</artifactId>
  <version>{version}</version>
  <scope>runtime</scope>
</dependency>

`

将CDI与HK2发现机制连接起来。 这是Official oracle Guideline

答案 2 :(得分:-1)

默认的beans.xml发现模式(在Java EE 7中)是#34;注释&#34;。这意味着只有具有CDI注释的bean才能被CDI识别和管理。

您的AccountJob类未注释。如果您希望CDI能够将服务注入其中,那么您需要使用一些范围注释来注释它,例如: @ApplicationScoped。

您的另一个选择是创建用于创建AccountJob bean的CDI生产者。看到: http://docs.jboss.org/weld/reference/latest/en-US/html_single/#_producer_methods