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

我曾经在Jersey REST资源中集成Service和DAO bean,在Java EE教程之后用@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(); } } 

我发现这个答案告诉使用DeltaSpike来完成Job,所以我将以下依赖项添加到我的pom.xml ,并且不向任何类添加任何代码行,对我的JobaccountService的注入工作正常

  org.apache.deltaspike.modules deltaspike-scheduler-module-api 1.7.2 compile   org.apache.deltaspike.modules deltaspike-scheduler-module-impl 1.7.2 runtime   org.apache.deltaspike.cdictrl deltaspike-cdictrl-api 1.7.2 compile   org.apache.deltaspike.cdictrl deltaspike-cdictrl-weld 1.7.2 runtime  

但是 ,我意识到当我从AccountService删除@Path("")时,它的实例仍然在ServiceResource注入,所以我的问题如下:

  1. 为什么添加DeltaSpike依赖项可以在不使用@Path情况下注入我的bean?
  2. 通过搜索更多,我明白DeltaSpike内部使用Weld进行注入,因为我已经使用GlassFish 4.0 ,我知道Weld已经存在,所以为什么注入在我的Job类和ServiceResource类中默认不起作用没有在我的bean上添加@Path ? 实际上为什么在Java教程中甚至建议添加@Path
  3. 是否有任何不良副作用,我在我的代码中没有看到,因为我认为我在这里混合多种DI方法而没有真正了解它们是如何工作的?

更新:经过更多搜索后,我意识到Jersey不使用Weld进行dependency injection,而是使用HK2 ,一个不同的框架也恰好是GlassFish的一部分,当我尝试注入AccountService而不使用@Path它显示了以下例外

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

因此,这会将问题更新为以下内容:

  1. 如何进行HK2注射? //不使用Java EE教程中提到的@Path
  2. 如果我设法用HK2DI ,那么使用DeltaSpike为Quartz Job做DI是否安全? 是否可以将两个CDI framewroks混合在一起扫描类并进行注入?

我把我的源代码放在pastebin上; pom.xml在这里 , Java就在这里

您不需要在AccountService CDI bean上设置Path注释。 如果在您的应用程序上启用了CDI(CDI 1.0中的空beans.xml或CDI> 1.0中的discovery-mode = all),则可以在JAX-RS资源中@Inject任何CDI 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 public class AccountService { public void Account get(String id){...} } 

您在post中链接的文章涉及混合EJB和CDI注释。 例如,您可以混合使用@Stateless@Path注释。 这很有趣,例如因为你可以:

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

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

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

编辑

对于你的上一个问题:

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

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

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

然后我们必须使用Jersey Extension

  org.glassfish.jersey.ext.cdi jersey-cdi1x-servlet {version} runtime  

`

将CDI与HK2发现机制连接起来。 这是官方的oracle指南

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

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

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