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

Jersey 2.26+Spring Boot 2下@Context变量被工厂重复创建问题

解决Jersey 2.26 + Spring Boot 2中@Context注入导致Factory重复创建及请求上下文异常的问题

问题根源分析

从你的代码和异常信息来看,这个问题主要来自两个核心点:

  1. Jersey 2.26对HK2依赖注入流程的调整:新版本中RequestScoped作用域的Factory实例化时机发生了变化,你的UserFactory在构造函数中直接初始化User,而此时HttpServletRequest还未绑定到当前请求上下文,导致后续抛出findOrCreate returned a null异常。
  2. @Context注解的特殊处理逻辑:@Context原本用于注入Jersey原生的上下文对象(如Request、Response等),对自定义类型使用@Context会触发额外的上下文查找流程,进而导致Factory被重复实例化(方法执行前后各一次)。

分步解决方案

1. 重构UserFactory,延迟User实例化到provide()方法

把User的创建逻辑从构造函数移到provide()方法中,确保在请求上下文完全就绪后再获取HttpServletRequest:

public class UserFactory implements Factory<User> {
    private final HttpServletRequest request;
    private final RequestIdentityService requestIdentityService;

    @Inject
    public UserFactory(HttpServletRequest request, RequestIdentityService requestIdentityService) {
        // 仅注入依赖,不做业务逻辑处理
        this.request = request;
        this.requestIdentityService = requestIdentityService;
    }

    @Override
    public User provide() {
        // 在此处创建User,此时请求上下文已就绪
        String userName = requestIdentityService.getCurrentUser(request);
        return new User(userName);
    }

    @Override
    public void dispose(User instance) { }
}

2. 替换@Context为@Inject注入自定义类型

对于自定义的User类型,使用Jersey/HK2标准的@Inject注解替代@Context,避免触发额外的上下文查找逻辑,减少Factory重复实例化的可能:

@GET @Path("/user-entitlements")
public Set<String> getUserEntitlements(@Inject User user) {
    return service.getUserEntitlements(user);
}

3. 确保Jersey与Spring上下文的桥接正确

如果RequestIdentityService是Spring管理的Bean,需要确保Jersey能正确访问Spring上下文。在你的Jersey配置类中显式注册Spring桥接Feature:

register(SpringComponentProviderFeature.class);

Spring Boot整合Jersey时,spring-boot-starter-jersey依赖已经包含了该Feature,但显式注册可以避免版本兼容问题。

4. 验证RequestScoped绑定的正确性

保持你的Binder配置不变,但确保使用的是Jersey提供的RequestScoped(org.glassfish.jersey.process.internal.RequestScoped),而非HK2的原生RequestScoped:

register(
    new AbstractBinder() {
        @Override
        public void configure() {
            bindFactory(UserFactory.class)
                .to(User.class)
                .in(org.glassfish.jersey.process.internal.RequestScoped.class);
        }
    }
);

为什么旧版本正常?

在Jersey 2.26之前,RequestScoped Factory的构造函数执行时机与请求上下文的绑定时机是同步的,因此在构造函数中直接获取HttpServletRequest不会出现null的情况;同时旧版本对@Context注解的处理逻辑更宽松,不会触发额外的Factory实例化流程。

内容的提问来源于stack exchange,提问作者Krzysztof Krasoń

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:56:46