我有一个使用嵌入式Tomcat 7的Spring Boot应用程序,并在我的application.properties
中设置了server.port = 0
以便获得随机端口。启动服务器并运行在某个端口后,我需要能够获取所选端口。
我无法使用@Value("$server.port")
因为它是零。这似乎是一个简单的信息,那么为什么我不能从我的Java代码中访问它呢?我该如何访问它?
我有一个使用嵌入式Tomcat 7的Spring Boot应用程序,并在我的application.properties
中设置了server.port = 0
以便获得随机端口。启动服务器并运行在某个端口后,我需要能够获取所选端口。
我无法使用@Value("$server.port")
因为它是零。这似乎是一个简单的信息,那么为什么我不能从我的Java代码中访问它呢?我该如何访问它?
是否也可以通过类似的方式访问管理端口,例如:
@SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT)
public class MyTest {
@LocalServerPort
int randomServerPort;
@LocalManagementPort
int randomManagementPort;
@LocalServerPort
只是@Value("${local.server.port}")
的一种快捷方式。 - deamonwebEnvironment = WebEnvironment.RANDOM_PORT
解决了问题。谢谢 - Muhammad MuzammilSpring的环境为您保存此信息。
@Autowired
Environment environment;
String port = environment.getProperty("local.server.port");
表面上看,这与注入一个带有@Value("${local.server.port}")
或@LocalServerPort
注释的字段相同(两者完全相同),在启动时会抛出自动装配失败的异常,因为该值在上下文完全初始化之前不可用。 这里的区别是该调用隐式地由运行时业务逻辑进行而不是在应用程序启动时调用,因此端口的'lazy-fetch'解决了该问题。
environment.getProperty("server.port")
可以。 - Anand Rockzzport
是 null
。@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
public class SpringBootH2IntegrationTest {
@Autowired
Environment environment;
@Test
public void test() {
String port = environment.getProperty("local.server.port"); // 现在可以看到端口号了
}
- tryingHard感谢 @Dirk Lachowski 指导我正确的方向。解决方案并不像我所期望的那么优雅,但我成功了。通过阅读 Spring 文档,我可以监听 EmbeddedServletContainerInitializedEvent 并在服务器启动运行后获取端口。这就是它的样子 -
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MyListener implements ApplicationListener<EmbeddedServletContainerInitializedEvent> {
@Override
public void onApplicationEvent(final EmbeddedServletContainerInitializedEvent event) {
int thePort = event.getEmbeddedServletContainer().getPort();
}
}
EmbeddedServletContainerInitializedEvent
,但是有一个类似的类叫做ServletWebServerInitializedEvent
,它有一个.getWebServer()
方法。这将至少获取Tomcat正在侦听的端口。 - NiteLite// Inject which port we were assigned
@Value("${local.server.port}")
int port;
@WebIntegrationTests
运行时,local.server.port
才会被设置。 - ejain为了使配置和我一样的应用程序受益于我经历过的问题...
以上解决方案都对我没有用,因为我在项目基础目录下有一个名为./config
的目录,其中包含2个文件:
application.properties
application-dev.properties
在application.properties
中,我有:
spring.profiles.active = dev # set my default profile to 'dev'
我在 application-dev.properties
文件中有以下内容:
server_host = localhost
server_port = 8080
当我从CLI运行我的fat jar时,*.properties
文件将从./config
目录中读取,一切都很好。
然而,事实证明这些属性文件完全覆盖了我在Spock规范中的@SpringBootTest
中设置的webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
。无论我尝试什么,即使将webEnvironment
设置为RANDOM_PORT
,Spring也总是会在端口8080上启动嵌入式Tomcat容器(或者我在./config/*.properties
文件中设置的任何值)。
我唯一能够克服这个问题的方法是在我的Spock集成规范中在@SpringBootTest
注释中添加一个明确的properties = "server_port=0"
:
@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "server_port=0")
只有在这种情况下,Spring 才会在一个随机端口上启动 Tomcat。个人认为这是 Spring 测试框架的一个 bug,但我相信他们会对此有自己的看法。
希望对某些人有所帮助。
从 Spring Boot 1.4.0 开始,您可以在测试中使用以下内容:
import org.springframework.boot.context.embedded.LocalServerPort;
@SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT)
public class MyTest {
@LocalServerPort
int randomPort;
// ...
}
在Spring Boot 2之后,有很多变化。上面给出的答案适用于Spring Boot 2之前的版本。如果您在运行应用程序时使用服务器端口的运行参数,则只会得到application.properties文件中提到的静态值@Value("${server.port}")
。现在要获取实际运行服务器的端口,请使用以下方法:
@Autowired
private ServletWebServerApplicationContext server;
@GetMapping("/server-port")
public String serverPort() {
return "" + server.getWebServer().getPort();
}
此外,如果您正在使用应用程序作为带有负载平衡RestTemplate
或WebClient
的Eureka/Discovery客户端,上述方法将返回确切的端口号。
这些解决方案都没有对我起作用。我需要在构建一个Swagger配置bean时知道服务器端口。使用ServerProperties 对我有用:
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.ApplicationPath;
import io.swagger.jaxrs.config.BeanConfig;
import io.swagger.jaxrs.listing.ApiListingResource;
import io.swagger.jaxrs.listing.SwaggerSerializers;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
@Component
@ApplicationPath("api")
public class JerseyConfig extends ResourceConfig
{
@Inject
private org.springframework.boot.autoconfigure.web.ServerProperties serverProperties;
public JerseyConfig()
{
property(org.glassfish.jersey.server.ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
}
@PostConstruct
protected void postConstruct()
{
// register application endpoints
registerAndConfigureSwaggerUi();
}
private void registerAndConfigureSwaggerUi()
{
register(ApiListingResource.class);
register(SwaggerSerializers.class);
final BeanConfig config = new BeanConfig();
// set other properties
config.setHost("localhost:" + serverProperties.getPort()); // gets server.port from application.properties file
}
}
这个例子使用了Spring Boot的自动配置和JAX-RS(而不是Spring MVC)。
我使用的是Spring 2.5.5和Junit 4.13.2,这是我的解决方案:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;
// tell Java the environment your testcase running is in Spring,
// which will enable the auto configuration such as value injection
@RunWith(SpringRunner.class)
@SpringBootTest(
class = Application.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SimpleWebTest {
@LocalServerPort
private int randomPort;
@Test
public void test() {
// use randomPort ...
System.out.println(randomPort);
}
}
你可以从中获取服务器端口
HttpServletRequest
@Autowired
private HttpServletRequest request;
@GetMapping(value = "/port")
public Object getServerPort() {
System.out.println("I am from " + request.getServerPort());
return "I am from " + request.getServerPort();
}