将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
,并且不向任何类添加任何代码行,对我的Job
的accountService
的注入工作正常
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
注入,所以我的问题如下:
- 为什么添加
DeltaSpike
依赖项可以在不使用@Path
情况下注入我的bean? - 通过搜索更多,我明白
DeltaSpike
内部使用Weld
进行注入,因为我已经使用GlassFish 4.0
,我知道Weld
已经存在,所以为什么注入在我的Job
类和ServiceResource
类中默认不起作用没有在我的bean上添加@Path
? 实际上为什么在Java教程中甚至建议添加@Path
? - 是否有任何不良副作用,我在我的代码中没有看到,因为我认为我在这里混合多种DI方法而没有真正了解它们是如何工作的?
更新:经过更多搜索后,我意识到Jersey
不使用Weld
进行dependency injection,而是使用HK2
,一个不同的框架也恰好是GlassFish
的一部分,当我尝试注入AccountService
而不使用@Path
它显示了以下例外
org.glassfish.hk2.api.UnsatisfiedDependencyException:SystemInjecteeImpl没有可用于注入的对象(requiredType = AccountService ,parent = ServiceResource ,qualifiers = {} …
因此,这会将问题更新为以下内容:
- 如何进行
HK2
注射? //不使用Java EE教程中提到的@Path
- 如果我设法用
HK2
做DI
,那么使用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