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

如何在Quarkus调度器中调用依赖RequestScoped Bean的服务?

问题描述

我有一个REST端点,调用依赖RequestScoped Bean的GreetingService,通过REST请求调用一切正常。但用Quarkus Scheduler创建定时任务定期调用该服务时,即便加了@ActivateRequestContext注解,还是抛出java.lang.IllegalStateException: No RESTEasy Reactive request in progress异常。

我不想修改现有服务(服务规模较大),也没法用外部定时任务(有权限控制问题),希望在调度器内部解决。目前发现用RestAssured调用端点的方式可行,但把测试依赖引入主代码是否合理?

可复现代码

资源类

@Path("/hello")
public class GreetingResource {

    @Inject
    GreetingService greetingService;

    @GET
    public String hello() {
        return greetingService.getGreetings();
    }
}

服务类

@ApplicationScoped
public class GreetingService {

    @Inject
    RequestBean requestBean;

    public String getGreetings() {

        //do logic, call other services, save to DB, etc

        if (requestBean.getAcceptLanguage().equals("en")) {
            return "Hello from RESTEasy Reactive";
        } else {
            return "Hola desde RESTEasy Reactive";
        }
    }
}

请求作用域Bean

@RequestScoped
public class RequestBean {

    private String acceptLanguage;

    RequestBean(HttpHeaders httpHeaders) {
        acceptLanguage = httpHeaders.getHeaderString(HttpHeaders.ACCEPT_LANGUAGE);
        if (acceptLanguage == null || acceptLanguage.isBlank()) {
            this.acceptLanguage = "en";
        }
    }

    public String getAcceptLanguage() {
        return acceptLanguage;
    }
}

调度器类

@ApplicationScoped
public class Scheduler {

    @Inject
    GreetingService greetingService;

    @Scheduled(every = "10s")
    @ActivateRequestContext
    public void scheduledTask() {

        try {
            Log.info("Scheduler is starting");
            greetingService.getGreetings();
            Log.info("Scheduler is finished");
        } catch (Exception e) {
            Log.error("Error while running scheduler", e);
        }

    }
}

相关依赖

<quarkus.platform.version>3.8.5</quarkus.platform.version>
...
<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-scheduler</artifactId>
</dependency>

解决方案

1. 不推荐引入RestAssured到主代码

RestAssured本质是测试工具,引入主代码会增加不必要的依赖体积,还可能带来测试相关的类冲突,不符合生产代码的依赖规范,不建议这么做。

2. 手动模拟RESTEasy Reactive请求上下文

@ActivateRequestContext仅能激活CDI请求上下文,但无法提供RESTEasy Reactive所需的请求对象,因此需要手动构建完整的请求上下文。修改调度器类如下:

@ApplicationScoped
public class Scheduler {

    @Inject
    GreetingService greetingService;

    @Inject
    RestEasyReactiveRequestContextFactory requestContextFactory;

    @Scheduled(every = "10s")
    public void scheduledTask() {
        try {
            Log.info("Scheduler is starting");
            // 构建模拟的HTTP请求头,可根据需求自定义
            Map<String, String> headers = new HashMap<>();
            headers.put(HttpHeaders.ACCEPT_LANGUAGE, "en");

            // 创建并激活RESTEasy Reactive请求上下文
            try (RestEasyReactiveRequestContext ctx = requestContextFactory.create(
                    new MockHttpRequest().headers(headers),
                    new MockHttpResponse())) {
                greetingService.getGreetings();
            }
            Log.info("Scheduler is finished");
        } catch (Exception e) {
            Log.error("Error while running scheduler", e);
        }
    }
}
  • 所需类RestEasyReactiveRequestContextFactory、MockHttpRequest、MockHttpResponse均属于quarkus-resteasy-reactive自带依赖,无需额外引入;
  • 可根据定时任务需求调整请求头参数,比如设置不同的Accept-Language默认值。

3. 替代方案:为RequestBean添加适配逻辑(极小修改)

如果允许对RequestBean做不影响现有逻辑的微小修改,可以添加一个供定时任务使用的构造方法:

@RequestScoped
public class RequestBean {

    private String acceptLanguage;

    // 原有REST请求用构造方法
    RequestBean(HttpHeaders httpHeaders) {
        acceptLanguage = httpHeaders.getHeaderString(HttpHeaders.ACCEPT_LANGUAGE);
        if (acceptLanguage == null || acceptLanguage.isBlank()) {
            this.acceptLanguage = "en";
        }
    }

    // 定时任务场景用构造方法,标注为备选实现
    @Alternative
    @Priority(1)
    public RequestBean() {
        this.acceptLanguage = "en"; // 设置默认值
    }

    public String getAcceptLanguage() {
        return acceptLanguage;
    }
}

之后在调度器中通过@Inject @Any Instance<RequestBean>选择这个备选实现即可。但如果你完全不想修改现有服务,优先选择方案2。


内容的提问来源于stack exchange,提问作者Janez Radešček

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 20:37:16