使用@TestConfiguration注入@LocalServerPort出现Failed to load ApplicationContext错误
问题根因
@LocalServerPort本质是读取Spring上下文环境中的local.server.port属性,这个属性只有在web容器完全启动、端口绑定完成后才会被填充到环境变量中。
而@TestConfiguration标注的配置类会在ApplicationContext刷新的早期阶段就被实例化、完成成员变量注入,此时web容器还没启动,local.server.port属性不存在,因此注入失败。
测试类的属性注入是在ApplicationContext完全刷新、web容器启动完成后才执行,因此可以正常注入@LocalServerPort。
解决方案
方案1(最推荐):将端口注入到@Bean方法的参数中
不要把@LocalServerPort标注在配置类的成员变量上,直接在需要用到端口的Bean方法参数上添加该注解,此时Bean的实例化在容器刷新后期执行,端口属性已经存在,不会报错。
示例代码:
@TestConfiguration public class MyTestConfiguration { @Bean public SomeBean someBean(@LocalServerPort int port) { // 直接使用参数中的port构造对象 return new SomeBean(port); } }
方案2:给配置类添加@Lazy注解
给配置类加@Lazy注解让配置类延迟初始化,等到测试类需要用到配置类中的Bean时再实例化配置类,此时web容器已经启动完成,端口属性已存在。
示例代码:
@Lazy @TestConfiguration public class MyTestConfiguration { @LocalServerPort private int port; @Bean public SomeBean someBean() { return new SomeBean(port); } }
注意:如果有其他非懒加载的Bean依赖该配置类中的Bean,会导致配置类提前初始化,该方案失效。
方案3:监听web容器初始化事件获取端口
实现ApplicationListener接口监听EmbeddedWebServerInitializedEvent事件,在事件触发时主动获取端口,避免提前注入。
示例代码:
import org.springframework.boot.web.context.EmbeddedWebServerInitializedEvent; import org.springframework.context.ApplicationListener; @TestConfiguration public class MyTestConfiguration implements ApplicationListener<EmbeddedWebServerInitializedEvent> { private int port; @Override public void onApplicationEvent(EmbeddedWebServerInitializedEvent event) { this.port = event.getWebServer().getPort(); } @Bean public SomeBean someBean() { return new SomeBean(port); } }
内容的提问来源于stack exchange,提问作者hellneck
相关产品推荐
相关产品推荐

