将 JAX-RS 与 CDI 集成的正确方法? [英] Correct way to Integrate JAX-RS with CDI?
问题描述
我曾经通过在 Java EE 教程
I used to integrate Service and DAO beans in Jersey REST resources by annotating them with @Path
following Java EE tutorial
一般来说,要让 JAX-RS 与企业 bean 一起工作,您需要使用 @Path 注释 bean 的类以将其转换为根资源类.您可以将 @Path 注释与无状态会话 bean 和单例 POJO bean 一起使用.
In general, for JAX-RS to work with enterprise beans, you need to annotate the class of a bean with @Path to convert it to a root resource class. You can use the @Path annotation with stateless session beans and singleton POJO beans.
所以我的代码曾经是这样的:
So my code used to be something like this:
@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 作业集成到我的应用程序中,我想找到一种方法将我的 AccountService
注入到这样的作业中
Now, I started integrating a Quartz Job into my application, and I wanted to find a way to inject my AccountService
inside a job like this
public class AccountJob implements Job {
@Inject
private AccountService accountService;
@Override
public void execute(JobExecutionContext jec) throws JobExecutionException {
accountService.updateAllAccounts();
}
}
我发现这个 answer 告诉我们使用 DeltaSpike
来完成这项工作,所以我在我的 pom.xml
中添加了以下依赖项,并且没有在任何类中添加任何代码行,accountService
到我的 Job
工作正常
I found this answer that tells to use DeltaSpike
to do the Job, so I added the following dependencies to my pom.xml
, and without adding any more lines of code to any class the inejection of accountService
to my Job
works fine
<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>
然而,我意识到当我从 AccountService
中删除 @Path("")
时,它的实例仍然被很好地注入到 @Path("")
code>ServiceResource,所以我的问题如下:
However, I realized that when I remove the @Path("")
from AccountService
, its instance is still injected fine inside ServiceResource
, so my questions are the following:
- 为什么添加
DeltaSpike
依赖项可以在不使用@Path
的情况下注入我的 bean? - 通过搜索更多,我了解到
DeltaSpike
内部使用Weld
进行注入,并且由于我已经在使用GlassFish 4.0
,我知道Weld
已经存在,那么为什么注入在我的Job
类和ServiceResource
类中默认不起作用而不添加@Path
在我的豆子上?实际上为什么Java教程中甚至建议添加@Path
? - 是否存在我在代码中没有看到的不良副作用,因为我认为我在这里混合了多个 DI 方法而没有真正了解它们是如何工作的?
- Why adding
DeltaSpike
dependencies made it possible to inject my beans without using@Path
on them? - By searching more, I understood that
DeltaSpike
internally usesWeld
to do the injection, and since I am already usingGlassFish 4.0
, I know thatWeld
is already there, so why the injection is not working by default in myJob
class and inServiceResource
class without adding@Path
on my beans? Actually why adding@Path
is even suggested in the Java tutorial? - Is there any bad side effects that I don't see in my code, because I think that I am mixing multiple DI methods here without really understanding how do they work?
更新: 经过更多的搜索,我发现Jersey
没有使用Weld
进行依赖注入,而是使用了HK2
,一个不同的框架,也恰好是 GlassFish
的一部分,当我尝试在不使用 @Path
的情况下注入 AccountService
时显示以下异常
Update: After more search, I realize that Jersey
doesn't use Weld
for dependency injection, instead it uses HK2
, a different framework that also happens to be a part of GlassFish
, when I try to inject AccountService
without using @Path
it shows the following exception
org.glassfish.hk2.api.UnsatisfiedDependencyException:在 SystemInjecteeImpl(requiredType=AccountService,parent=ServiceResource,qualifiers={} 处没有可注入的对象...
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=AccountService,parent=ServiceResource,qualifiers={}...
所以这将问题更新为以下内容:
So this updates the questions to the following:
- 如何使
HK2
注入工作?//不使用 Java EE 教程中提到的@Path
- 如果我设法用
HK2
做DI
,使用DeltaSpike
做DI
是否安全> 为 Quartz 工作?可以将两个 CDI 框架混合在一起来扫描类并进行注入吗?
- How to make
HK2
injections works? // Without using@Path
as mentioned in the Java EE Tutorial - If I managed to to do
DI
withHK2
, will it be safe to useDeltaSpike
to doDI
for the Quartz Job? Is it okay to mix two CDI framewroks together to scan the classes and do the injection?
我把我的源代码放在了 pastebin 上;pom.xml
是 这里,Java
是
I put my my source code on pastebin; pom.xml
is here and the Java
is here
推荐答案
您不需要在 AccountService
CDI bean 上设置 Path
注释.如果在您的应用程序上启用了 CDI(在 CDI 1.0 中使用空 beans.xml 或在 CDI > 1.0 中使用 discovery-mode=all),您可以@Inject
JAX-RS 资源中的任何 CDI bean.所以你只需要编写以下类:
You do not need to set the Path
annotation on your AccountService
CDI bean. If CDI is enabled on your application (either with empty beans.xml in CDI 1.0 or discovery-mode=all in CDI > 1.0), you can @Inject
any CDI bean in your JAX-RS resource.
So you just have to write the following class:
@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){...}
}
您在帖子中链接的文章涉及混合 EJB 和 CDI 注释.例如,您可以混合使用 @Stateless
和 @Path
注释.例如,这很有趣,因为您可以:
The article you linked in your post deals with mixing EJB and CDI annotations. For example you can mix @Stateless
and @Path
annotations. It's interesting for example because you can :
- EJB 事务在您的 Rest 资源中的好处(即使现在您可以使用
@Transactional
拦截器绑定) - 设置资源池
- 等
请注意,所有这些都不需要 deltaspike 依赖的帮助.
Note that all of this works without the help of deltaspike dependency.
对于您的第二个问题,由于 Quartz 管理自己的线程,CDI 不处理类,因此您不能在 Quartz 类中注入 bean.deltaspike 模块的目的是允许在 Quartz 作业中注入 CDI bean.在内部,deltaspike 控制 CDI 上下文.
For your second question, as Quartz manages its own threads, classes are not handled by CDI so you can not inject beans in Quartz classes. The aim of the deltaspike module is to allow injecting CDI beans in Quartz Jobs. Internally, deltaspike controls CDI Contexts.
编辑
最后的问题:
您的 HK2 问题很确定是由于缺少依赖项(在您的应用程序或服务器中).正如之前的评论中所说,我设法使用您提供的源文件在 Glassfish 4(内部版本 89)上部署了您的应用程序.
Your HK2 problem comes pretty sure from a missing dependency (in your application or server). As said in a previous comment, I managed to deploy your App on Glassfish 4 (build 89) with the source files you provided.
关于 CDI 与 Quartz 的集成,我认为最好的方法是实现您自己的 JobFactory
并使用 BeanManager
实例化您的作业.看看这个链接:https://devsoap.com/注入-cdi-managed-beans-into-quarz-jobs/
Regarding the integration of CDI with Quartz, I think the best is to implement your own JobFactory
and instanciate your jobs using BeanManager
. Take a look at this link : https://devsoap.com/injecting-cdi-managed-beans-into-quarz-jobs/
这篇关于将 JAX-RS 与 CDI 集成的正确方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!