{@code TestSocketUtils} can be used in integration tests which start an + * external server on an available random port. However, these utilities make no + * guarantee about the subsequent availability of a given port and are therefore + * unreliable. Instead of using {@code TestSocketUtils} to find an available local + * port for a server, it is recommended that you rely on a server's ability to + * start on a random ephemeral port that it selects or is assigned by the + * operating system. To interact with that server, you should query the server + * for the port it is currently using. + * + * @since 3.2 + */ +public class TestSocketUtils { + + /** + * The minimum value for port ranges used when finding an available TCP port. + */ + static final int PORT_RANGE_MIN = 1024; + + /** + * The maximum value for port ranges used when finding an available TCP port. + */ + static final int PORT_RANGE_MAX = 65535; + + private static final int PORT_RANGE_PLUS_ONE = PORT_RANGE_MAX - PORT_RANGE_MIN + 1; + + private static final int MAX_ATTEMPTS = 1_000; + + private static final Random random = new Random(System.nanoTime()); + + private static final TestSocketUtils INSTANCE = new TestSocketUtils(); + + private TestSocketUtils() { + } + + /** + * Find an available TCP port randomly selected from the range [1024, 65535]. + * @return an available TCP port number + * @throws IllegalStateException if no available port could be found + */ + public static int findAvailableTcpPort() { + return INSTANCE.findAvailableTcpPortInternal(); + } + + + /** + * Internal implementation of {@link #findAvailableTcpPort()}. + *
Package-private solely for testing purposes. + */ + int findAvailableTcpPortInternal() { + int candidatePort; + int searchCounter = 0; + do { + Assert.assertTrue(++searchCounter <= MAX_ATTEMPTS, String.format( + "Could not find an available TCP port in the range [%d, %d] after %d attempts", + PORT_RANGE_MIN, PORT_RANGE_MAX, MAX_ATTEMPTS)); + candidatePort = PORT_RANGE_MIN + random.nextInt(PORT_RANGE_PLUS_ONE); + } + while (!isPortAvailable(candidatePort)); + + return candidatePort; + } + + /** + * Determine if the specified TCP port is currently available on {@code localhost}. + *
Package-private solely for testing purposes.
+ */
+ boolean isPortAvailable(int port) {
+ try {
+ ServerSocket serverSocket = ServerSocketFactory.getDefault()
+ .createServerSocket(port, 1, InetAddress.getByName("localhost"));
+ serverSocket.close();
+ return true;
+ }
+ catch (Exception ex) {
+ return false;
+ }
+ }
+
+}
diff --git a/1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider/src/main/resources/application.yml b/1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider/src/main/resources/application.yml
index 37a249fdcc..24dc62758e 100644
--- a/1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider/src/main/resources/application.yml
+++ b/1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider/src/main/resources/application.yml
@@ -27,3 +27,10 @@ dubbo:
address: zookeeper://127.0.0.1:2181
metadata-report:
address: zookeeper://127.0.0.1:2181
+ service:
+ org:
+ apache:
+ dubbo:
+ springboot:
+ demo:
+ serialization: fastjson2
diff --git a/1-basic/dubbo-samples-spring-boot/pom.xml b/1-basic/dubbo-samples-spring-boot/pom.xml
index d558cc3e81..d7132bb298 100644
--- a/1-basic/dubbo-samples-spring-boot/pom.xml
+++ b/1-basic/dubbo-samples-spring-boot/pom.xml
@@ -109,10 +109,28 @@