问题
I'm new to Spring integration.
Working with Spring 4, Only java anotations.
The project where i'm working now we set up tcp connection in a property file.
At the momet it is hardcoded to only 2 different connections and it must be changed to a more dynamic approach where we can set up a variable amount of them in the property file and be able to add new ones at runtime.
I'm aware of the existence of dynamic tcp client example and tried to base my work on it.
First we set up the following bean for the connection:
@Bean(name = "node1TCPConnection")
public AbstractClientConnectionFactory node1TCPConnection() {
final TcpNetClientConnectionFactory tcpNetClientConnectionFactory = new TcpNetClientConnectionFactory(
env.getProperty("socket.tcp.nodes[0].ip"),
env.getProperty("socket.tcp.nodes[0].port", Integer.class)
);
tcpNetClientConnectionFactory.setSingleUse(false);
tcpNetClientConnectionFactory.setSoKeepAlive(true);
final ByteArrayLengthHeaderSerializer by = new ByteArrayLengthHeaderSerializer(headBytes);
tcpNetClientConnectionFactory.setSerializer(by);
tcpNetClientConnectionFactory.setDeserializer(by);
return tcpNetClientConnectionFactory;
}
Then we have the adapter who waits for something to sent:
@Bean
public TcpReceivingChannelAdapter node1TcpReaderClient(
@Qualifier("node1TCPConnection") final AbstractClientConnectionFactory connectionFactory) {
final TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(connectionFactory);
adapter.setClientMode(true);
adapter.setErrorChannelName("errorChannel");
adapter.setRetryInterval(retryInterval);
adapter.setOutputChannel(fromTcp());
return adapter;
}
When fromTcp() is called it transforms the message and the following code sends it to another application for further processing.
@ServiceActivator(inputChannel = "fromTcp")
public void outbound(final String inMessage, final @Headers Map<String, Object> headerMap) {
sendToApi(inMessage, headerMap);
}
When the message is procesed we have to send a response.
@Bean
@ServiceActivator(inputChannel = "toTcpCh01")
public TcpSendingMessageHandler tcpOutGateCh01(
final @Qualifier("node1TCPConnection") AbstractClientConnectionFactory connectionFactory) {
final TcpSendingMessageHandler tcpSendingMsgHandler = new TcpSendingMessageHandler();
tcpSendingMsgHandler.setConnectionFactory(connectionFactory);
return tcpSendingMsgHandler;
}
and by using a gateway:
@MessagingGateway()
public interface MessageTcpGateway {
@Gateway(requestChannel = "toTcpCh01")
ListenableFuture<Void> sendTcpChannel01(@Header("host") String host, byte[] inMessage);
}
we send it back.
With the example I can understand how to dynamically create a flow for the response.
But I can't fathom how to create a common connection pool and then create listening adapters and response adapters on the fly based on those connectionsfactory and then closing/removing them on runtime.
I somewhat understand how to make a flow with an inbound adapter thanks to this question
Do I need to create multiple separate IntegrationFlow for each adapter? so all the calls and responses can be handled asynchronous ( I may be wrong about the asynchrony)
and then handle them separatly when wanting to close a connection? like calling close to the TcpReceivingChannelAdapter and then to TcpSendingMessageHandler and finally deregistering the connectonfactory?
回答1:
I don't this that for Collaborating Channel Adapters you need separate IntegrationFlow
definitions for the TcpReceivingChannelAdapter
and TcpSendingMessageHandler
. It really can be done as a single IntegrationFlow
starting from the TcpReceivingChannelAdapter
and ending with the TcpSendingMessageHandler
. The point is that IntegrationFlow
per se is just a logical container to group components references. The hard work is really done by all those components you declare there and with this TcpReceivingChannelAdapter
to TcpSendingMessageHandler
and gateway in between you are really going to be async.
Please, keep in mind that ByteArrayLengthHeaderSerializer
has to be declared as a bean as well. Not sure that you need a separate instance for each dynamic flow, but here is an API to do that from there anyway:
/**
* Add an object which will be registered as an {@link IntegrationFlow} dependant bean in the
* application context. Usually it is some support component, which needs an application context.
* For example dynamically created connection factories or header mappers for AMQP, JMS, TCP etc.
* @param bean an additional arbitrary bean to register into the application context.
* @return the current builder instance
*/
IntegrationFlowRegistrationBuilder addBean(Object bean);
来源:https://stackoverflow.com/questions/50874121/dynamic-generation-of-tcp-client-with-inbound-channel-and-respond-channel