spring-boottcpspring-integrationtcplistenerspring-events

Spring integration: Issue with Listening to TcpConnectionOpenEvent and TcpConnectionCloseEvent along with interceptors


I'm working with Spring Integration and trying to handle TcpConnectionOpenEvent and TcpConnectionCloseEvent to collect metrics on the connections and to write to the log. However, I'm not able to listen to these events properly. This is working without interceptors But when I'm adding the interceptor-factory-chain as below the events listener is not works.

Could you provide guidance on how to properly set up event listeners for these connection events?

Here are the relevant configurations I have:

<int-ip:tcp-connection-factory id="crLfServer"
                                   using-nio="false"
                                   deserializer="serverDeserializer"
                                   serializer="serverSerializer"
                                   single-use="false"
                                   lookup-host="false"
                                   type="server"
                                   **interceptor-factory-chain="serverConnectionInterceptorFactoryChain"**
                                   task-executor="incomingTaskExecutor"
                                   ssl-context-support="${sslcontext.server.beanname}"
                                   socket-support="requireClientAuthSocketSupport"
                                   port="${local.server.port}"/>

<int-ip:tcp-inbound-gateway id="gatewayCrLf"
                                reply-timeout="${pos.server.timeout}"
                                connection-factory="crLfServer"
                                request-channel="serverInChannelPos"
                                reply-channel="serverOutChannelPos"
                                error-channel="errorChannel" />


 <int:channel id="serverOutChannelPos">
        <int:interceptors>
            <ref bean="serverOutInterceptor"/>
            <ref bean="errorMessageChannelInterceptor"/>
        </int:interceptors>
    </int:channel>


    <int:channel id="serverInChannelPos">
        <int:interceptors>
            <ref bean="serverInInterceptor"/>
        </int:interceptors>
    </int:channel>

I've also added an event listener class:

@Component
@Slf4j
public class TcpConnectionEventListener {

    @EventListener
    public void handleTcpConnectionOpen(TcpConnectionOpenEvent event) {
        log.info("TCP connection opened: {}", event.getConnectionId());
        //collect metrics
        //some other actions...
    }

    @EventListener
    public void handleTcpConnectionClose(TcpConnectionCloseEvent event) {
        log.info("TCP connection closed: {}", event.getConnectionId());
        //collect metrics
        //some other actions...
    }
}
  @Bean
    @Lazy
    public TcpConnectionInterceptorFactoryChain serverConnectionInterceptorFactoryChain(){
        TcpConnectionInterceptorFactoryChain tcpConnectionInterceptorFactoryChain = new TcpConnectionInterceptorFactoryChain();
        TcpConnectionInterceptorFactory[] tcpConnectionInterceptorFactories = {
                serverRetailerNumberValidationInterceptorFactory(),
                serverStoringConnectionIdInterceptorFactory()};
        tcpConnectionInterceptorFactoryChain.setInterceptors(tcpConnectionInterceptorFactories);
        return tcpConnectionInterceptorFactoryChain;
    }

The issue is that I don't see any logs from the @EventListener methods, and it seems they are not triggered at all. Could you help me identify what might be wrong and how to get these events to work properly along with interceptors?


Solution

  • So, after some local testing here is a conclusion.

    When you use TcpConnectionInterceptorFactoryChain, you have to ensure that TcpConnectionInterceptorFactory produces TcpConnectionInterceptorSupport supplied with an ApplicationEventPublisher. For example like this:

    public class HelloWorldInterceptorFactory implements
            TcpConnectionInterceptorFactory, ApplicationEventPublisherAware {
    
            
        private volatile ApplicationEventPublisher applicationEventPublisher;
    
        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
            this.applicationEventPublisher = applicationEventPublisher;
        }
    
        @Override
        public TcpConnectionInterceptorSupport getInterceptor() {
            return new HelloWorldInterceptor(this.hello, this.world, this.applicationEventPublisher);
        }
    
    }
    

    The ConnectionFactory is supplied with one automatically, but it is not its responsibility to mutate interceptor instances supplied by the mentioned factory. Therefore it is target project responsibility to wire interceptors properly if we'd like to emit the mentioned events.