tutorial - spring boot web
Spring Boot: cómo obtener el puerto de ejecución (7)
¿También es posible acceder al puerto de administración de manera similar, por ejemplo:
@SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT)
public class MyTest {
@LocalServerPort
int randomServerPort;
@LocalManagementPort
int randomManagementPort;
Tengo una aplicación de inicio de Spring (usando Tomcat 7 integrado), y configuré
server.port = 0
en mi
application.properties
para poder tener un puerto aleatorio.
Después de que el servidor se inicia y se ejecuta en un puerto, necesito poder obtener el puerto que se eligió.
No puedo usar
@Value("$server.port")
porque es cero.
Esta es una información aparentemente simple, entonces, ¿por qué no puedo acceder a ella desde mi código Java?
¿Cómo puedo acceder?
A partir de Spring Boot 1.4.0 puede usar esto en su prueba:
@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "server_port=0")
Así que otros que han configurado sus aplicaciones como la mía se benefician de lo que pasé ...
Ninguna de las soluciones anteriores funcionó para mí porque tengo un directorio
./config
justo debajo de mi base de proyecto con 2 archivos:
application.properties
application-dev.properties
En
application.properties
tengo:
// Inject which port we were assigned
@Value("${local.server.port}")
int port;
En
application-dev.properties
tengo:
import org.springframework.boot.context.embedded.LocalServerPort;
@SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT)
public class MyTest {
@LocalServerPort
int randomPort;
// ...
}
Esto es así cuando ejecuto mi jarra desde la CLI, los archivos
*.properties
se leerán desde el directorio
./config
y todo estará bien.
Bueno, resulta que estos archivos de propiedades anulan por completo la
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
en
@SpringBootTest
en mis especificaciones de Spock.
No importa lo que intenté, incluso con
webEnvironment
configurado en
RANDOM_PORT
Spring siempre iniciaría el contenedor Tomcat incorporado en el puerto 8080 (o cualquier valor que haya configurado en mis archivos
./config/*.properties
).
La
ÚNICA
forma en que pude superar esto fue agregando unas
properties = "server_port=0"
explícitas
properties = "server_port=0"
a la anotación
@SpringBootTest
en mis especificaciones de integración de Spock:
spring.profiles.active = dev # set my default profile to ''dev''
Entonces, y solo entonces Spring finalmente comenzó a hacer girar a Tomcat en un puerto aleatorio. En mi humilde opinión, este es un error de marco de prueba de primavera, pero estoy seguro de que tendrán su propia opinión al respecto.
Espero que esto haya ayudado a alguien.
Gracias a @Dirk Lachowski por señalarme en la dirección correcta. La solución no es tan elegante como me hubiera gustado, pero la hice funcionar. Al leer los documentos de Spring, puedo escuchar en el EmbeddedServletContainerInitializedEvent y obtener el puerto una vez que el servidor está en funcionamiento. Así es como se ve:
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();
}
}
Ninguna de estas soluciones funcionó para mí. Necesitaba conocer el puerto del servidor mientras construía un bean de configuración Swagger. Usar ServerProperties funcionó para mí:
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
}
}
Este ejemplo utiliza la configuración automática de Spring Boot y JAX-RS (no Spring MVC).
Puede obtener el puerto que está utilizando una instancia de Tomcat incrustada durante las pruebas inyectando el valor local.server.port como tal:
server_host = localhost
server_port = 8080
Spring''s Environment contiene esta información para usted.
@Autowired
Environment environment;
String port = environment.getProperty("local.server.port");
En la superficie, esto parece idéntico a inyectar un campo anotado
@Value("${local.server.port}")
(o
@LocalServerPort
, que es idéntico), por lo que se arroja una falla de cableado automático al inicio ya que el valor no está disponible hasta que el contexto esté completamente inicializado.
La diferencia aquí es que esta llamada se realiza implícitamente en la lógica de negocios en tiempo de ejecución en lugar de invocarse al inicio de la aplicación, y por lo tanto, la ''recuperación lenta'' del puerto se resuelve bien.