You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Integration UDP入站适配器自动端口获取失败求助

Ah, I see the issue here! You're hitting a classic race condition where you're trying to fetch the assigned port before the UDP adapter has finished starting up and binding to the random port provided by the OS.

When you set the port to 0, the actual port allocation doesn't happen until the adapter's start() method runs. Even though IntegrationFlowContext.registration(flow).register() triggers startup (since autoStartup defaults to true), this process isn't immediate—your code calls source.getPort() right after registration, before the socket has been fully bound.

Solution 1: Wait for the Adapter to Bind (Simple Approach)

You can modify your makeANewUdpInbound method to wait until the adapter finishes binding to the port before returning it. This uses a retry loop to avoid race conditions:

public UnicastReceivingChannelAdapter makeANewUdpInbound(int port) {
    System.out.println("Creating an adapter to receive from port " + port);
    UnicastReceivingChannelAdapter source = new UnicastReceivingChannelAdapter(port);
    IntegrationFlow flow = IntegrationFlows.from(source)
            .<byte[], String>transform(String::new)
            .handle(System.out::println)
            .get();
    IntegrationFlowRegistration registration = flowContext.registration(flow).register();

    // Handle random port scenario
    if (port == 0) {
        int retryCount = 15; // Adjust based on your environment
        while (retryCount-- > 0 && source.getPort() == 0) {
            try {
                Thread.sleep(100); // Short wait before checking again
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Interrupted waiting for port binding", e);
            }
        }
        if (source.getPort() == 0) {
            throw new IllegalStateException("Failed to bind to a random port after retries");
        }
        // Update registration map with the actual port (not 0)
        registrations.put(source.getPort(), registration);
        System.out.println("Adapter bound to random port: " + source.getPort());
    } else {
        registrations.put(port, registration);
    }

    return source;
}

Solution 2: Listen for ListeningEvent (More Reliable Approach)

For production code, a better approach is to listen for Spring Integration's ListeningEvent, which is published after the adapter successfully binds to the port. This removes any reliance on arbitrary sleep intervals:

@Autowired
private ApplicationEventPublisher eventPublisher;

public UnicastReceivingChannelAdapter makeANewUdpInbound(int port) {
    System.out.println("Creating an adapter to receive from port " + port);
    UnicastReceivingChannelAdapter source = new UnicastReceivingChannelAdapter(port);
    
    // Register listener for port binding confirmation
    source.addListener(new ApplicationListener<ListeningEvent>() {
        @Override
        public void onApplicationEvent(ListeningEvent event) {
            UnicastReceivingChannelAdapter adapter = (UnicastReceivingChannelAdapter) event.getSource();
            int actualPort = adapter.getPort();
            System.out.println("Adapter is now listening on port: " + actualPort);
            // Replace temporary 0 key with actual port in registrations map
            registrations.put(actualPort, registrations.remove(0));
        }
    });

    IntegrationFlow flow = IntegrationFlows.from(source)
            .<byte[], String>transform(String::new)
            .handle(System.out::println)
            .get();
    IntegrationFlowRegistration registration = flowContext.registration(flow).register();

    if (port == 0) {
        registrations.put(0, registration); // Temporary key until actual port is known
    } else {
        registrations.put(port, registration);
    }

    return source;
}

Key Notes

  • In your original code, storing registrations with key 0 would cause conflicts if you create multiple random-port adapters. Always use the actual assigned port as the map key.
  • The ListeningEvent approach is more robust because it reacts directly to the port binding event, eliminating guesswork about timing.

内容的提问来源于stack exchange,提问作者Kurobara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:58:15