Spring integration 使用Spring集成并发读取CSV文件
我想使用spring集成并发处理CSV文件。每一行都将转换为单独的消息。所以假设CSV文件中有10K行,我想启动10个线程,每一行都将传递给这个线程。如果有人能给我举个例子就好了 感谢从Spring integration 使用Spring集成并发读取CSV文件,spring-integration,Spring Integration,我想使用spring集成并发处理CSV文件。每一行都将转换为单独的消息。所以假设CSV文件中有10K行,我想启动10个线程,每一行都将传递给这个线程。如果有人能给我举个例子就好了 感谢从开始支持迭代器作为有效负载进行拆分。因此,如果的输出通道是执行通道,则可以将入站文件转换为行迭代器,并并行处理每行的消息: <splitter input-channel="splitChannel" output-channel="executorChannel" expression
开始支持迭代器作为有效负载进行拆分。因此,如果
的输出通道是执行通道,则可以将入站文件
转换为行迭代器
,并并行处理每行的消息:
<splitter input-channel="splitChannel" output-channel="executorChannel"
expression="T(org.apache.commons.io.FileUtils).lineIterator(payload)"/>
我正在使用Spring Integration 4.1.0,并尝试了您的建议,但它似乎对我不起作用。
今天我对它进行了一些研究,现在倾向于将其作为SpringIntegration4.1.0的bug
看看我的解释是否有道理
如果您尝试此示例,您将看到它将起作用(注意,这不是使用您的SpEL示例):
使用您的SpEL示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:int="http://www.springframework.org/schema/integration" xmlns:int-file="http://www.springframework.org/schema/integration/file" xmlns:int-stream="http://www.springframework.org/schema/integration/stream" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<int:inbound-channel-adapter id="exchangeReplayFileAdapter" ref="exchangeReplayFileReadingMessageSource" method="receive" auto-startup="true" channel="channel1">
<int:poller fixed-delay="10000000" />
</int:inbound-channel-adapter>
<bean id="exchangeReplayFileReadingMessageSource" class="org.springframework.integration.file.FileReadingMessageSource">
<property name="directory" value="/tmp/inputdir" />
</bean>
<int:channel id="channel1">
<int:dispatcher task-executor="taskExecutor" />
</int:channel>
<int:splitter input-channel="channel1" output-channel="channel2">
<bean class="com.xxx.common.util.springintegration.FileSplitter" />
</int:splitter>
<int:channel id="channel2"></int:channel>
<int-stream:stdout-channel-adapter channel="channel2"></int-stream:stdout-channel-adapter>
<task:executor id="taskExecutor" pool-size="1" />
</beans>
<int:splitter input-channel="exchangeReplayFiles" output-channel="exchangeSpringQueueChannel"
expression="T(org.apache.commons.io.FileUtils).lineIterator(payload)"/>
以及expressionevaluationmessageprocessor
类:
/**
* A {@link MessageProcessor} implementation that evaluates a SpEL expression
* with the Message itself as the root object within the evaluation context.
*
* @author Mark Fisher
* @author Artem Bilan
* @since 2.0
*/
public class ExpressionEvaluatingMessageProcessor<T> extends AbstractMessageProcessor<T> {
private final Expression expression;
private final Class<T> expectedType;
...
/**
* Create an {@link ExpressionEvaluatingMessageProcessor} for the given expression
* and expected type for its evaluation result.
* @param expression The expression.
* @param expectedType The expected type.
*/
public ExpressionEvaluatingMessageProcessor(Expression expression, Class<T> expectedType) {
Assert.notNull(expression, "The expression must not be null");
try {
this.expression = expression;
this.expectedType = expectedType;
}
catch (ParseException e) {
throw new IllegalArgumentException("Failed to parse expression.", e);
}
}
/**
* Processes the Message by evaluating the expression with that Message as the
* root object. The expression evaluation result Object will be returned.
* @param message The message.
* @return The result of processing the message.
*/
@Override
public T processMessage(Message<?> message) {
return this.evaluateExpression(this.expression, message, this.expectedType);
}
...
}
由于ArrayList
实际上是一个集合
,因此它永远不会到达设置迭代器的逻辑,因此也不会在produceOutput(…)
方法中调用迭代器上的next()
那么为什么LineIterator
会被关联到ArrayList
?我相信ExpressionEvaluationSpliter中有一个缺陷,它总是这样做:
public ExpressionEvaluatingSplitter(Expression expression) {
super(new ExpressionEvaluatingMessageProcessor(expression, List.class));
}
我认为在SpringIntegration4中,它现在应该查看表达式计算结果的类型(一个列表
或一个迭代器
),然后调用super(可能需要重新设计如何完成,因为在调用JVM不允许的super之前要确定类型)
你觉得怎么样?谢谢你的回答。4.0之前怎么样?恐怕我可以迁移到Spring 4.0!。我很好,即使它读取第一个完整文件并创建多个线程的消息来处理。
/**
* A {@link MessageProcessor} implementation that evaluates a SpEL expression
* with the Message itself as the root object within the evaluation context.
*
* @author Mark Fisher
* @author Artem Bilan
* @since 2.0
*/
public class ExpressionEvaluatingMessageProcessor<T> extends AbstractMessageProcessor<T> {
private final Expression expression;
private final Class<T> expectedType;
...
/**
* Create an {@link ExpressionEvaluatingMessageProcessor} for the given expression
* and expected type for its evaluation result.
* @param expression The expression.
* @param expectedType The expected type.
*/
public ExpressionEvaluatingMessageProcessor(Expression expression, Class<T> expectedType) {
Assert.notNull(expression, "The expression must not be null");
try {
this.expression = expression;
this.expectedType = expectedType;
}
catch (ParseException e) {
throw new IllegalArgumentException("Failed to parse expression.", e);
}
}
/**
* Processes the Message by evaluating the expression with that Message as the
* root object. The expression evaluation result Object will be returned.
* @param message The message.
* @return The result of processing the message.
*/
@Override
public T processMessage(Message<?> message) {
return this.evaluateExpression(this.expression, message, this.expectedType);
}
...
}
public abstract class AbstractMessageSplitter extends AbstractReplyProducingMessageHandler {
protected final Object handleRequestMessage(Message<?> message) {
Object result = this.splitMessage(message);
// return null if 'null'
if (result == null) {
return null;
}
Iterator<Object> iterator;
final int sequenceSize;
if (result instanceof Collection) {
Collection<Object> items = (Collection<Object>) result;
sequenceSize = items.size();
iterator = items.iterator();
}
else if (result.getClass().isArray()) {
Object[] items = (Object[]) result;
sequenceSize = items.length;
iterator = Arrays.asList(items).iterator();
}
else if (result instanceof Iterable<?>) {
sequenceSize = 0;
iterator = ((Iterable<Object>) result).iterator();
}
else if (result instanceof Iterator<?>) {
sequenceSize = 0;
iterator = (Iterator<Object>) result;
}
else {
sequenceSize = 1;
iterator = Collections.singleton(result).iterator();
}
if (!iterator.hasNext()) {
return null;
}
final MessageHeaders headers = message.getHeaders();
final Object correlationId = headers.getId();
final AtomicInteger sequenceNumber = new AtomicInteger(1);
return new FunctionIterator<Object, AbstractIntegrationMessageBuilder<?>>(iterator,
new Function<Object, AbstractIntegrationMessageBuilder<?>>() {
@Override
public AbstractIntegrationMessageBuilder<?> apply(Object object) {
return createBuilder(object, headers, correlationId, sequenceNumber.getAndIncrement(),
sequenceSize);
}
});
}
public ExpressionEvaluatingSplitter(Expression expression) {
super(new ExpressionEvaluatingMessageProcessor(expression, List.class));
}