Tengo una aplicación de inicio de la primavera (usando incrustado Tomcat 7), y me he fijado server.port = 0
en mi application.properties
para que pueda tener un puerto aleatorio. Una vez 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 ella?
spring
spring-boot
port
embedded-tomcat-7
Fatigar
fuente
fuente
Respuestas:
¿También es posible acceder al puerto de administración de una manera similar, por ejemplo:
@SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT) public class MyTest { @LocalServerPort int randomServerPort; @LocalManagementPort int randomManagementPort;
fuente
@LocalServerPort
es solo un atajo para@Value("${local.server.port}")
.Spring's Environment tiene 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), mediante el cual se produce una falla de cableado automático al inicio, ya que el valor no está disponible hasta que el contexto se inicializa por completo. La diferencia aquí es que esta llamada se realiza implícitamente en la lógica empresarial en tiempo de ejecución en lugar de invocarse al inicio de la aplicación y, por lo tanto, la 'recuperación diferida' del puerto se resuelve correctamente.fuente
environment.getProperty("server.port")
hizo.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 primavera, 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(); } }
fuente
PortProvider
y proporcioné ungetPort()
método. Me conecté automáticamentePortProvider
al controlador que necesitaba el puerto, y cuando mi lógica comercial llamóportProvider.getPort()
, se devolvió el puerto de tiempo de ejecución.EmbeddedServletContainerInitializedEvent
, pero hay una clase similar llamadaServletWebServerInitializedEvent
que tiene un.getWebServer()
método. Esto le dará al menos el puerto que está escuchando Tomcat.Solo para que otros que han configurado sus aplicaciones como la mía se beneficien de lo que pasé ...
Ninguna de las soluciones anteriores funcionó para mí porque tengo un
./config
directorio justo debajo de la base de mi proyecto con 2 archivos:application.properties
application-dev.properties
En
application.properties
tengo:spring.profiles.active = dev # set my default profile to 'dev'
En
application-dev.properties
tengo:server_host = localhost server_port = 8080
Esto es así cuando ejecuto mi fat jar desde la CLI, los
*.properties
archivos se leerán desde el./config
directorio y todo estará bien.Bueno, resulta que estos archivos de propiedades anulan completamente la
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
configuración@SpringBootTest
en mis especificaciones de Spock. No importa lo que he intentado, incluso conwebEnvironment
sistema deRANDOM_PORT
resorte que siempre se inicie el contenedor Tomcat incluido en el puerto 8080 (o cualquier valor que había puesto en mis./config/*.properties
archivos).La ÚNICA forma en que pude superar esto fue agregando un explícito
properties = "server_port=0"
a la@SpringBootTest
anotación en mis especificaciones de integración de Spock:@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "server_port=0")
Entonces, y solo entonces, Spring finalmente comenzó a activar Tomcat en un puerto aleatorio. En mi humilde opinión, este es un error del marco de prueba de Spring, pero estoy seguro de que tendrán su propia opinión al respecto.
Espero que esto haya ayudado a alguien.
fuente
Puede obtener el puerto que está siendo utilizado por una instancia de Tomcat incorporada durante las pruebas inyectando el valor local.server.port como tal:
// Inject which port we were assigned @Value("${local.server.port}") int port;
fuente
local.server.port
solo se establece cuando se ejecuta con@WebIntegrationTests
A partir de Spring Boot 1.4.0, puede usar esto en su prueba:
import org.springframework.boot.context.embedded.LocalServerPort; @SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT) public class MyTest { @LocalServerPort int randomPort; // ... }
fuente
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 usa la configuración automática Spring Boot y JAX-RS (no Spring MVC).
fuente
Después de Spring Boot 2, muchas cosas han cambiado. Las respuestas dadas anteriormente funcionan antes de Spring Boot 2. Ahora, si está ejecutando su aplicación con argumentos de tiempo de ejecución para el puerto del servidor, entonces solo obtendrá el valor estático con
@Value("${server.port}")
, que se menciona en el archivo application.properties . Ahora, para obtener el puerto real en el que se está ejecutando el servidor, utilice el siguiente método:@Autowired private ServletWebServerApplicationContext server; @GetMapping("/server-port") public String serverPort() { return "" + server.getWebServer().getPort(); }
Además, si está utilizando sus aplicaciones como Eureka / Discovery Clients con carga balanceada
RestTemplate
oWebClient
, el método anterior devolverá el número de puerto exacto.fuente
Puede obtener el puerto del servidor desde el
@Autowired private HttpServletRequest request; @GetMapping(value = "/port") public Object getServerPort() { System.out.println("I am from " + request.getServerPort()); return "I am from " + request.getServerPort(); }
fuente
Asegúrese de haber importado el paquete correcto.
import org.springframework.core.env.Environment;
y luego usa el objeto Environment
@Autowired private Environment env; // Environment Object containts the port number @GetMapping("/status") public String status() { return "it is runing on"+(env.getProperty("local.server.port")); }
fuente
Lo resolví con una especie de proxy bean. El cliente se inicializa cuando es necesario, para entonces el puerto debería estar disponible:
@Component public class GraphQLClient { private ApolloClient apolloClient; private final Environment environment; public GraphQLClient(Environment environment) { this.environment = environment; } public ApolloClient getApolloClient() { if (apolloClient == null) { String port = environment.getProperty("local.server.port"); initApolloClient(port); } return apolloClient; } public synchronized void initApolloClient(String port) { this.apolloClient = ApolloClient.builder() .serverUrl("http://localhost:" + port + "/graphql") .build(); } public <D extends Operation.Data, T, V extends Operation.Variables> GraphQLCallback<T> graphql(Operation<D, T, V> operation) { GraphQLCallback<T> graphQLCallback = new GraphQLCallback<>(); if (operation instanceof Query) { Query<D, T, V> query = (Query<D, T, V>) operation; getApolloClient() .query(query) .enqueue(graphQLCallback); } else { Mutation<D, T, V> mutation = (Mutation<D, T, V>) operation; getApolloClient() .mutate(mutation) .enqueue(graphQLCallback); } return graphQLCallback; } }
fuente