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
相关产品推荐
相关产品推荐

