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

Micronaut 4升级后Filter与Controller中@RequestScope Bean实例不一致的问题求助

Micronaut 4升级后Filter与Controller中@RequestScope Bean实例不一致的问题求助

我最近把项目升级到了Micronaut 4 + Java 21,结果遇到了一个特别头疼的问题:我想通过@RequestScope的Bean在HttpServerFilter和Controller之间共享请求状态——具体是在Controller里设置请求的成功/失败状态,然后让Filter在Controller执行完成后读取这个状态打最终的汇总日志。但现在Filter里拿到的Bean实例和Controller里的根本不是同一个,导致我在Controller里设置的状态在Filter里读出来全是null!

之前用Micronaut 3 + Java 17的时候这段代码完全正常,升级后就出问题了,我排查了好久都没找到原因,求大家帮忙看看!


我的代码实现

1. 接口与@RequestScope Bean

我定义了一个通用的SummaryInfo接口,然后用@RequestScope的RequestInfo实现类来存请求专属数据:

// 通用接口
public interface SummaryInfo {
    SummaryEnum getSummaryEnum();
    void setSummaryEnum(SummaryEnum summaryEnum);
    Map<String, Object> getIdentifiers();
}
// Request-Scoped 实现类
import io.micronaut.runtime.http.scope.RequestScope;
import lombok.Data;
import java.util.Collections;
import java.util.Map;

@Data
@RequestScope
public class RequestInfo implements SummaryInfo {
    private SummaryEnum summaryEnum;
    private String customerId;

    @Override
    public Map<String, Object> getIdentifiers() {
        return Collections.singletonMap("customerId", customerId);
    }
}

2. 日志Filter

我的Filter是单例,直接注入了SummaryInfo Bean:

import io.micronaut.http.filter.HttpServerFilter;
import io.micronaut.http.filter.ServerFilterChain;
import jakarta.inject.Inject;
import reactor.core.publisher.Mono;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Filter("/**")
public class SummaryLoggingFilter implements HttpServerFilter {
    private static final Logger log = LoggerFactory.getLogger(SummaryLoggingFilter.class);

    @Inject
    private SummaryInfo summaryInfo;

    @Override
    public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
        log.info("Filter (before): Got bean instance {}", summaryInfo.hashCode());
        // 这里的hashCode和Controller里的完全不一样
        return Mono.from(chain.proceed(request))
                .doOnNext(response -> {
                    log.info("Filter (after): Got bean instance {}", summaryInfo.hashCode());
                    log.info("Summary enum: {}", summaryInfo.getSummaryEnum()); 
                    // 问题就在这!这里getSummaryEnum()返回null
                });
    }
}

3. Controller

Controller也是单例,直接注入了RequestInfo(或者SummaryInfo我都试过):

import jakarta.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.annotation.PathVariable;

@Controller
public class MyController {
    private static final Logger log = LoggerFactory.getLogger(MyController.class);

    @Inject
    private RequestInfo requestInfo;

    @Post("/hello/{customerId}")
    public Response hello(@PathVariable String customerId) {
        log.info("Controller: Got bean instance {}", requestInfo.hashCode());
        // 这里的hashCode和Filter里的完全不同
        requestInfo.setCustomerId(customerId);
        requestInfo.setSummaryEnum(ExampleSummaryEnum.SUCCESS);
        log.info("Controller: Set summaryEnum to SUCCESS");
        
        Response response = new Response();
        response.setMessage("world!");
        return response;
    }

    // 内部Response类
    public static class Response {
        private String message;
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
    }
}

我已经尝试过的排查方法

  • 核对Micronaut文档:我仔细看了Micronaut的Bean作用域文档,按照文档说明,@RequestScope的Bean在同一个请求生命周期内应该只有一个实例,而且给单例Bean(比如Filter这种单例)注入的应该是代理对象,代理会自动指向当前请求的真实实例。
  • 改用Provider注入:我看到文档里说给单例注入窄作用域Bean的时候推荐用jakarta.inject.Provider,所以我把Filter和Controller里的注入都改成了Provider<SummaryInfo>,然后用provider.get()获取实例,但结果还是一样——Filter和Controller里拿到的实例hashCode完全不同,Filter里还是读不到设置的状态。

我的困惑

我本来以为同一个HTTP请求里,Filter和Controller拿到的代理对象应该指向同一个RequestInfo实例,但日志里的hashCode明显不一样,说明是两个不同的真实实例。明明之前Micronaut3的时候完全正常,升级到4之后就出问题了,到底是我哪里的代码写法不对,还是Micronaut4有什么我没注意到的变化?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 11:52:59