Sending Data to External Systems Using TCP with Spring Integration Data can be sent to external systems using various protocols such as HTTP, HTTP/2, and WebSockets. For minimal overhead, TCP communication is a viable alternative.

Before diving into TCP with Spring Integration, let’s first explore basic TCP communication using Netcat.

Setting Up a TCP Listener with Netcat

To create a TCP server that listens for incoming connections, open your terminal and execute the following command:

nc -l 127.0.0.1 8080

This command will start a TCP server on port 8080 of your local machine.

Sending Data to the TCP Server To send data to the server, open a new terminal window and execute the following command:

nc 127.0.0.1 8080

Now, both the server and client are connected via TCP. You can type messages, and they will be visible on both ends.

Using TCP in Spring Integration

Now that we understand the basics of TCP, let’s implement it using Spring Integration.

Create a new Spring project and add the spring-integration-ip package by including the following dependency in your pom.xml:

<!-- Add spring-integration-ip dependency -->
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-ip</artifactId>
    <version>6.4.1</version>
</dependency>

Create a TCP Connection Factory Configuration

Create a new file named tcp-connection-factory.xml in the resources/META-INF directory and add the following content:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://www.springframework.org/schema/integration"
             xmlns:ip="http://www.springframework.org/schema/integration/ip"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
                                 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
                                 http://www.springframework.org/schema/integration/ip https://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd
                                 http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd">

    <!-- Serializer to handle data format -->
    <beans:bean id="fastestWireFormatSerializer" class="org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer"/>

    <!-- Define client-side connection factory -->
    <ip:tcp-connection-factory id="clientConnFactory"
                               type="client"
                               host="localhost"
                               port="8080"
                               single-use="false"
                               serializer="fastestWireFormatSerializer"
                               deserializer="fastestWireFormatSerializer"
                               so-timeout="10000"/>

    <!-- Caching client connection factory -->
    <beans:bean id="cacheTcp" class="org.springframework.integration.ip.tcp.connection.CachingClientConnectionFactory">
        <beans:constructor-arg ref="clientConnFactory"/>
        <beans:constructor-arg value="10"/>
        <beans:property name="connectionWaitTimeout" value="1200"/>
    </beans:bean>

    <!-- Define inbound and outbound channels -->
    <channel id="inbound"/>
    <channel id="outbound"/>

    <!-- Configure outbound adapter for sending messages -->
    <ip:tcp-outbound-channel-adapter id="outAdapter.client"
                                     channel="outbound"
                                     auto-startup="true"
                                     connection-factory="cacheTcp"/>

    <!-- Configure inbound adapter for receiving replies -->
    <ip:tcp-inbound-channel-adapter id="inAdapter.client"
                                    channel="inbound"
                                    auto-startup="true"
                                    connection-factory="cacheTcp"/>

    <!-- Service Activator to handle received messages -->
    <service-activator input-channel="inbound" ref="runMethod" method="run"/>
</beans:beans>

Implement the Main Java Class

In your main Java class, you can write the following code to test the TCP communication:

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.messaging.support.GenericMessage;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("Starting server...");
        // Load Spring context configuration
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/META-INF/spring/integration/tcpClientServerDemo-conversion-context.xml");

        // Retrieve the outbound channel bean
        DirectChannel dc = context.getBean("outbound", DirectChannel.class);

        // Send messages continuously
        int i = 0;
        while (true) {
            dc.send(new GenericMessage<>("Hello World \r\n" + i++));
            Thread.sleep(10);
        }
    }

    // Method to handle received replies
    public static void run(String resp) {
        System.out.println("REPLY RECEIVED --- " + resp);
    }
}

This configuration defines the connection factory for both the server and client. The client is configured to connect to localhost on port 8080. Channels: The inbound and outbound channels are used for receiving and sending messages, respectively. Service Activator: The runMethod bean is invoked when a message is received on the inbound channel.