Eu tenho um aplicativo de inicialização de primavera (usando tomcat 7 incorporado) e configurei server.port = 0
no meu application.properties
para que possa ter uma porta aleatória. Depois que o servidor é inicializado e executado em uma porta, preciso conseguir a porta que foi escolhida.
Não posso usar @Value("$server.port")
porque é zero. Esta é uma informação aparentemente simples, então por que não consigo acessá-la do meu código Java? Como posso acessá-lo?
spring
spring-boot
port
embedded-tomcat-7
Tucker
fonte
fonte
Respostas:
Também é possível acessar a porta de gerenciamento de forma semelhante, por exemplo:
@SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT) public class MyTest { @LocalServerPort int randomServerPort; @LocalManagementPort int randomManagementPort;
fonte
@LocalServerPort
é apenas um atalho para@Value("${local.server.port}")
.O ambiente do Spring guarda essas informações para você.
@Autowired Environment environment; String port = environment.getProperty("local.server.port");
Superficialmente, isso parece idêntico a injetar um campo anotado
@Value("${local.server.port}")
(ou@LocalServerPort
, que é idêntico), por meio do qual uma falha de autowiring é lançada na inicialização, pois o valor não está disponível até que o contexto seja totalmente inicializado. A diferença aqui é que essa chamada está sendo feita implicitamente na lógica de negócios do tempo de execução, em vez de ser invocada na inicialização do aplicativo e, portanto, o 'lazy-fetch' da porta resolve ok.fonte
environment.getProperty("server.port")
funcionou.Obrigado a @Dirk Lachowski por me apontar na direção certa. A solução não é tão elegante quanto eu gostaria, mas fiz funcionar. Lendo os documentos de primavera, posso ouvir no EmbeddedServletContainerInitializedEvent e obter a porta assim que o servidor estiver instalado e funcionando. Aqui está o que parece -
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(); } }
fonte
PortProvider
e fornecendo umgetPort()
método. Autowired myPortProvider
in para o controlador que precisa da porta, e quando minha lógica de negócios chamouportProvider.getPort()
, a porta runtime foi retornada.EmbeddedServletContainerInitializedEvent
, mas existe uma classe semelhante chamadaServletWebServerInitializedEvent
que possui um.getWebServer()
método. Isso lhe dará a porta que o Tomcat está escutando.Apenas para que outras pessoas que configuraram seus aplicativos como o meu se beneficiem do que eu passei ...
Nenhuma das soluções acima funcionou para mim porque tenho um
./config
diretório logo abaixo da base do meu projeto com 2 arquivos:application.properties
application-dev.properties
Em
application.properties
eu tenho:spring.profiles.active = dev # set my default profile to 'dev'
Em
application-dev.properties
eu tenho:server_host = localhost server_port = 8080
Isto é, quando eu executo meu jar de gordura a partir da CLI, os
*.properties
arquivos serão lidos do./config
diretório e está tudo bem.Bem, acontece que esses arquivos de propriedades substituem completamente a
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
configuração@SpringBootTest
em minhas especificações de Spock. Não importa o que eu tentei, mesmo comwebEnvironment
definido comoRANDOM_PORT
Spring, sempre inicializaria o contêiner Tomcat integrado na porta 8080 (ou qualquer valor que eu definisse em meus./config/*.properties
arquivos).A ÚNICA maneira de superar isso foi adicionando um texto explícito
properties = "server_port=0"
à@SpringBootTest
anotação em minhas especificações de integração do Spock:@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "server_port=0")
Então, e só então, o Spring finalmente começou a girar o Tomcat em uma porta aleatória. IMHO, este é um bug do framework de testes do Spring, mas tenho certeza que eles terão suas próprias opiniões sobre isso.
Espero que isso tenha ajudado alguém.
fonte
Você pode obter a porta que está sendo usada por uma instância incorporada do Tomcat durante os testes, injetando o valor local.server.port como tal:
// Inject which port we were assigned @Value("${local.server.port}") int port;
fonte
local.server.port
só é definido quando executado com@WebIntegrationTests
A partir do Spring Boot 1.4.0, você pode usar isso em seu teste:
import org.springframework.boot.context.embedded.LocalServerPort; @SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT) public class MyTest { @LocalServerPort int randomPort; // ... }
fonte
Nenhuma dessas soluções funcionou para mim. Eu precisava saber a porta do servidor ao construir um bean de configuração Swagger. Usar ServerProperties funcionou para mim:
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 exemplo usa a configuração automática Spring Boot e JAX-RS (não Spring MVC).
fonte
Depois do Spring Boot 2, muita coisa mudou. As respostas fornecidas acima funcionam antes do Spring Boot 2. Agora, se você estiver executando seu aplicativo com argumentos de tempo de execução para a porta do servidor, obterá apenas o valor estático com
@Value("${server.port}")
, que é mencionado no arquivo application.properties . Agora, para obter a porta real na qual o servidor está sendo executado, use o seguinte método:@Autowired private ServletWebServerApplicationContext server; @GetMapping("/server-port") public String serverPort() { return "" + server.getWebServer().getPort(); }
Além disso, se você estiver usando seus aplicativos como clientes Eureka / Discovery com balanceamento de carga
RestTemplate
ouWebClient
, o método acima retornará o número de porta exato.fonte
Você pode obter a porta do servidor do
@Autowired private HttpServletRequest request; @GetMapping(value = "/port") public Object getServerPort() { System.out.println("I am from " + request.getServerPort()); return "I am from " + request.getServerPort(); }
fonte
Certifique-se de que importou o pacote correto
import org.springframework.core.env.Environment;
e então usar o 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")); }
fonte
Eu resolvi isso com uma espécie de bean proxy. O cliente é inicializado quando necessário, então a porta deve estar disponível:
@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; } }
fonte