web-dev-qa-db-fra.com

Spring Boot - Comment obtenir le port en cours d'exécution

J'ai une application de démarrage printanière (avec Tomcat 7 intégré) et j'ai défini server.port = 0 Dans mon application.properties Pour pouvoir utiliser un port aléatoire. Une fois le serveur démarré et fonctionnant sur un port, je dois pouvoir obtenir le port qui a été choisi.

Je ne peux pas utiliser @Value("$server.port") parce que c'est zéro. C'est une information apparemment simple, alors pourquoi ne puis-je pas y accéder à partir de mon code Java? Comment puis-je y accéder?)

57
Tucker

Merci à @Dirk Lachowski de m'avoir orienté dans la bonne direction. La solution n'est pas aussi élégante que je l'aurais souhaité, mais je la fais fonctionner. En lisant la documentation print, je peux écouter sur EmbeddedServletContainerInitializedEvent et obtenir le port une fois le serveur opérationnel. Voici à quoi ça ressemble -

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();
      }
    }
19
Tucker

Est-il également possible d’accéder au port de gestion de la même manière, par exemple:

  @SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT)
  public class MyTest {

    @LocalServerPort
    int randomServerPort;

    @LocalManagementPort
    int randomManagementPort;
68
LaughingLemon

Spring's Environment détient ces informations pour vous.

@Autowired
Environment environment;

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

En surface, cela semble identique à l’injection d’un champ annoté @Value("${local.server.port}") (ou @LocalServerPort, Identique), un échec de l'auto-câblage étant renvoyé au démarrage, la valeur n'étant disponible que lorsque le contexte est complètement initialisé. La différence réside dans le fait que cet appel est implicitement passé dans la logique métier d'exécution plutôt que d'être appelé au démarrage de l'application, d'où la résolution correcte du port.

53
hennr

Vous pouvez obtenir le port utilisé par une instance intégrée de Tomcat lors des tests en injectant la valeur local.server.port en tant que telle:

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

À partir de Spring Boot 1.4.0, vous pouvez l’utiliser dans votre test:

import org.springframework.boot.context.embedded.LocalServerPort;

@SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT)
public class MyTest {

  @LocalServerPort
  int randomPort;

  // ...
}
11
jabal

Juste pour que ceux qui ont configuré leurs applications comme la mienne profitent de ce que j'ai vécu ...

Aucune des solutions ci-dessus n'a fonctionné pour moi car j'ai un répertoire ./config Juste sous ma base de projet avec 2 fichiers:

application.properties
application-dev.properties

Dans application.properties, J'ai:

spring.profiles.active = dev  # set my default profile to 'dev'

Dans application-dev.properties J'ai:

server_Host = localhost
server_port = 8080

C’est le cas lorsque je lance mon gros fichier jar à partir de la CLI. Les fichiers *.properties Sont lus à partir du répertoire ./config Et c’est bon.

Eh bien, il se trouve que ces fichiers de propriétés remplacent complètement le paramètre webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT Dans @SpringBootTest Dans mes spécifications Spock. Quoi que j'aie essayé, même avec webEnvironment défini sur RANDOM_PORT, Spring démarrera toujours le conteneur Tomcat intégré sur le port 8080 (ou la valeur que j'aurais définie dans mes fichiers ./config/*.properties ).

La manière SEULEMENT que j'ai pu surmonter cela était en ajoutant un properties = "server_port=0" Explicite à l'annotation @SpringBootTest Dans mon intégration Spock Spécifications:

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

Alors, et seulement alors, Spring a finalement commencé à faire tourner Tomcat sur un port aléatoire. IMHO c'est un bogue du framework de test de Spring, mais je suis sûr qu'ils auront leur propre opinion à ce sujet.

J'espère que cela a aidé quelqu'un.

11
Jacomoman

Aucune de ces solutions n'a fonctionné pour moi. J'avais besoin de connaître le port du serveur lors de la construction d'un bean de configuration Swagger. Utiliser ServerProperties a fonctionné pour moi:

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         
    }
}

Cet exemple utilise la configuration automatique Spring Boot et JAX-RS (pas Spring MVC).

6
mre