You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WildFly中CDI 4.0与Jakarta REST 3.1集成的Bean生命周期疑问

WildFly中JAX-RS @Dependent资源的@PreDestroy未执行问题

我正在研究WildFly中JAX-RS与CDI的集成,重点关注Bean的生命周期表现,但实际行为和预期不符。

代码示例

REST资源类

@Dependent
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
public class UserResourceImpl {

   @PostConstruct
   public void init() {
    System.out.println("UserResourceImpl init ...");
   }

   @PreDestroy
   public void destroy() {
    System.out.println("UserResourceImpl destroy ...");
   }

   @GET
   public Response test() {
    return Response.ok("{ \"answer\": \"working...\"}").build();
   }
 }

beans.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans version="4.0"
   xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
      https://jakarta.ee/xml/ns/jakartaee
      https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
   bean-discovery-mode="annotated">

</beans>

Bean发现模式设置为annotated,目的是精准控制Bean生命周期。

问题现象

部署到WildFly 32后,每个HTTP请求都会触发@PostConstruct方法,但请求完成后、甚至应用终止时,@PreDestroy始终没有执行。

根据RESTEasy文档,未显式定义作用域的REST根资源会绑定到@RequestScoped,我原本预期这个标注了@Dependent的Bean会表现得和@RequestScoped类似,每个请求完成时触发@PreDestroy,请问这是什么原因?是Bug吗?


问题原因分析

这不是WildFly或RESTEasy的Bug,完全是CDI @Dependent作用域的特性导致的:

  • @Dependent是CDI的“依赖作用域”,它没有自己的独立上下文,Bean的生命周期完全由它的“持有者”控制。持有者创建实例后,用完如果没有显式触发销毁逻辑,CDI容器不会主动调用@PreDestroy。
  • 对于标注了@Dependent的JAX-RS根资源,RESTEasy会在每个请求到来时创建实例,但请求处理完成后,RESTEasy并不会将实例交还给CDI容器进行销毁操作,也不会主动调用@PreDestroy——因为@Dependent Bean的销毁责任在持有者(这里就是RESTEasy的请求处理逻辑),而RESTEasy并没有实现这个销毁逻辑。

你提到的“未显式定义作用域的REST根资源绑定到Request作用域”是正确的默认行为,但那只适用于没有显式标注任何作用域的情况:此时RESTEasy会自动为根资源添加@RequestScoped,Bean属于请求上下文,请求结束时CDI容器会清理上下文,自然触发@PreDestroy。但显式标注@Dependent后,就会遵循该作用域的规则,不再触发默认的@RequestScoped绑定。

解决方案

如果想要每个请求完成时触发@PreDestroy,直接将@Dependent替换为@RequestScoped即可:

@RequestScoped
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
public class UserResourceImpl {
    // 原有代码保持不变
}

你的beans.xml设置的是bean-discovery-mode="annotated",@RequestScoped属于CDI作用域注解,符合“annotated”的Bean发现规则,这个Bean会被CDI容器正确识别和管理,请求结束时@PreDestroy会正常执行。

补充说明

别混淆@Dependent和@RequestScoped的核心差异:

  • @RequestScoped:拥有独立的请求上下文,请求开始时创建实例,请求结束时由CDI容器统一销毁,一定会触发@PreDestroy。
  • @Dependent:没有自己的上下文,实例的生命周期完全依附于持有者,除非持有者主动调用销毁逻辑,否则@PreDestroy不会执行。

内容的提问来源于stack exchange,提问作者office.aizaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:52:43