Spring Boot – Как получить текущий порт

У меня есть приложение загрузки весны (с использованием встроенного tomcat 7), и я установил server.port = 0 в моих application.properties чтобы у меня был случайный порт. После того, как сервер загрузился и запущен на порту, мне нужно получить порт, который был выбран.

Я не могу использовать @Value("$server.port") потому что он равен нулю. Это, казалось бы, простая часть информации, поэтому почему я не могу получить доступ к ней из своего java-кода? Как я могу получить к нему доступ?

Возможно ли также получить доступ к порту управления, например:

  @SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT) public class MyTest { @LocalServerPort int randomServerPort; @LocalManagementPort int randomManagementPort; 

Spring’s Environment хранит эту информацию для вас.

 @Autowired Environment environment; String port = environment.getProperty("local.server.port"); 

На @Value("${local.server.port}") взгляд это выглядит так же, как и инъекция поля, аннотированного @Value("${local.server.port}") (или @LocalServerPort , который идентичен), в результате чего при запуске возникает отказ автоустройства, поскольку значение недоступно пока контекст не будет полностью инициализирован. Разница здесь в том, что этот вызов неявно делается в бизнес-логике времени выполнения, а не вызван при запуске приложения, и, следовательно, «ленивый выбор» порта разрешает нормально.

Спасибо @Dirk Lachowski за то, что он указал мне в правильном направлении. Решение не так элегантно, как мне бы хотелось, но я получил его работу. Читая весенние документы, я могу прослушивать EmbeddedServletContainerInitializedEvent и получать порт после запуска и запуска сервера. Вот как это выглядит:

 import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component public class MyListener implements ApplicationListener { @Override public void onApplicationEvent(final EmbeddedServletContainerInitializedEvent event) { int thePort = event.getEmbeddedServletContainer().getPort(); } } 

Вы можете получить порт, который используется встроенным экземпляром Tomcat во время тестов, введя значение local.server.port как таковое:

 // Inject which port we were assigned @Value("${local.server.port}") int port; 

Начиная с 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; // ... } 

Ни одно из этих решений не работало для меня. Мне нужно было знать порт сервера при построении компонента конфигурации Swagger. Использование 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).

Просто так, что другие, которые настроили свои приложения, такие как мои, выиграли от того, что я прошел …

Ни один из вышеперечисленных решений не работал для меня, потому что у меня есть каталог ./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, файлы *.properties будут считаны из ./config и все это хорошо.

Ну, оказывается, что эти файлы свойств полностью переопределяют параметр webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT в @SpringBootTest в моих спецификациях Spock. Независимо от того, что я пробовал, даже с установкой webEnvironment в RANDOM_PORT Spring всегда RANDOM_PORT встроенный контейнер Tomcat на порт 8080 (или любое RANDOM_PORT значение, которое я установил бы в своих файлах ./config/*.properties ).

Единственный способ, которым я смог преодолеть это, заключался в добавлении явных properties = "server_port=0" в аннотацию @SpringBootTest в моих спецификациях интеграции Spock:

 @SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "server_port=0") 

Затем, и только тогда весна наконец начала разворачивать Tomcat на случайном порту. ИМХО это ошибка весны тестирования Spring, но я уверен, что у них будет собственное мнение об этом.

Надеюсь, это помогло кому-то.

Давайте будем гением компьютера.