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

fuj*_*ujy 7 java rest jax-rs quartz-scheduler jakarta-ee

我曾经通过使用@Path以下Java EE 教程对其进行注释来将服务和 DAO bean 集成到 Jersey REST 资源中

一般来说,要让 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){...}
}
Run Code Online (Sandbox Code Playgroud)

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

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

  @Override
  public void execute(JobExecutionContext jec) throws JobExecutionException {
    accountService.updateAllAccounts();
  }
}
Run Code Online (Sandbox Code Playgroud)

我发现这个答案告诉使用DeltaSpike来完成工作,所以我将以下依赖项添加到我的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>
Run Code Online (Sandbox Code Playgroud)

但是,我意识到当我删除@Path("")from 时AccountService,它的实例仍然被很好地注入到内部ServiceResource,所以我的问题如下:

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

更新:经过更多搜索后,我意识到它JerseyWeld用于依赖注入,而是使用HK2了一个不同的框架,该框架也恰好是 的一部分GlassFish,当我尝试在AccountService不使用@Path它的情况下注入时显示以下异常

org.glassfish.hk2.api.UnsatisfiedDependencyException: SystemInjecteeImpl(requiredType= AccountService ,parent= ServiceResource ,qualifiers={}...

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

  1. 如何使HK2注射有效?// 不使用@PathJava EE 教程中提到的
  2. 如果我设法DI使用HK2,使用它DeltaSpike来执行DIQuartz 工作是否安全?可以将两个 CDI 框架混合在一起来扫描类并进行注入吗?

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

Rou*_*boy 4

您不需要PathAccountServiceCDI bean 上设置注释。如果您的应用程序启用了 CDI(在 CDI 1.0 中使用空 beans.xml 或在 CDI > 1.0 中使用 discovery-mode=all),您可以@Inject在 JAX-RS 资源中使用任何 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){...}
}
Run Code Online (Sandbox Code Playgroud)

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

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

请注意,所有这些都无需 deltaspike 依赖项的帮助即可完成。

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

编辑

对于您的最后一个问题:

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

  • 关于 CDI 与 Quartz 的集成,我认为最好的方法是实现您自己的JobFactory并使用BeanManager. 看看这个链接:https://devsoap.com/injecting-cdi-management-beans-into-quarz-jobs/