控制器中webServerPort字段为何被重置?
问题原因及解决办法
核心原因
@Validated注解会让Spring为MyController创建代理对象,导致事件监听的原始实例和请求处理的代理实例是两个不同的对象,各自的webServerPort字段独立存储值。
具体细节:
- 当类上标注
@Validated时,Spring会通过AOP生成代理类来实现JSR-380参数校验逻辑,此时容器中同时存在MyController的原始实例和代理实例。 @EventListener注解绑定在父类的方法上,事件触发时会调用原始实例的onApplicationEvent方法,因此原始实例的webServerPort被设置为8080。- 但处理HTTP请求时,Spring路由到的是代理实例的
readStates方法,代理实例继承的webServerPort从未被赋值,所以返回int类型的默认值0。
解决方案
方案1:将端口字段改为静态变量
修改父类的webServerPort为静态字段,让原始实例和代理实例共享同一个变量值:
public abstract class AbstractController { @EventListener void onApplicationEvent(final ReactiveWebServerInitializedEvent event) { webServerPort = event.getWebServer().getPort(); log.debug("webServerPort: {}", webServerPort); } @Getter private static int webServerPort; // 改为static }
方案2:移除Controller上的@Validated(如果不需要校验)
如果接口不需要参数校验,直接去掉MyController上的@Validated注解,Spring就不会生成代理,控制器实例唯一,字段值会保持一致。
方案3:拆分事件监听逻辑到独立Bean
把端口监听逻辑抽成单独的组件类,避免和控制器耦合,然后在控制器中注入该组件获取端口:
@Component public class ServerPortHolder { private int webServerPort; @EventListener void onApplicationEvent(final ReactiveWebServerInitializedEvent event) { webServerPort = event.getWebServer().getPort(); log.debug("webServerPort: {}", webServerPort); } public int getWebServerPort() { return webServerPort; } } @Validated @RestController class MyController { private final ServerPortHolder portHolder; // 构造注入 public MyController(ServerPortHolder portHolder) { this.portHolder = portHolder; } @GetMapping(path = "/") Mono<Void> readStates(final ServerHttpResponse response) { log.debug("webServerPort: {}", portHolder.getWebServerPort()); // ... 其他逻辑 } }
方案4:通过Environment获取端口
直接从Spring环境中获取端口值,无需监听事件:
@Validated @RestController class MyController { private final Environment environment; public MyController(Environment environment) { this.environment = environment; } @GetMapping(path = "/") Mono<Void> readStates(final ServerHttpResponse response) { int webServerPort = environment.getProperty("server.port", Integer.class, 0); log.debug("webServerPort: {}", webServerPort); // ... 其他逻辑 } }
内容的提问来源于stack exchange,提问作者Jin Kwon
相关产品推荐
相关产品推荐

