Mule ESB - FileMessageReceiver中的ConcurrentModificationException

时间:2015-01-07 09:42:04

标签: java mule

My Mule应用程序处理几个不同的目录,它会移动文件。我有一些文件入站端点和文件连接器。我有情况需要轮询不同的文件夹,处理文件,移动它们,再次轮询等。

我在日志中看到了这个异常:

java.util.ConcurrentModificationException
    at java.util.ArrayList.sort(ArrayList.java:1456)
    at java.util.Collections.sort(Collections.java:175)
    at org.mule.transport.file.FileMessageReceiver.poll(FileMessageReceiver.java:199)
    at org.mule.transport.AbstractPollingMessageReceiver.performPoll(AbstractPollingMessageReceiver.java:216)
    at org.mule.transport.PollingReceiverWorker.poll(PollingReceiverWorker.java:80)
    at org.mule.transport.PollingReceiverWorker.run(PollingReceiverWorker.java:49)
    at org.mule.transport.TrackingWorkManager$TrackeableWork.run(TrackingWorkManager.java:267)
    at org.mule.work.WorkerContext.run(WorkerContext.java:286)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

此处抛出异常:http://grepcode.com/file/repo1.maven.org/maven2/org.mule.transports/mule-transport-file/3.5.0/org/mule/transport/file/FileMessageReceiver.java#199

我注意到在这种情况下http://grepcode.com/file/repo1.maven.org/maven2/org.mule.transports/mule-transport-file/3.5.0/org/mule/transport/file/FileMessageReceiver.java#675每次都返回相同的集合对象files.isEmpty() - 这不是理想的,很可能是导致问题的原因。

现在,幸运的是,这个异常并不具有破坏性,除非它可能会跳过轮询周期并污染日志。

之前有人见过/想法吗?

3 个答案:

答案 0 :(得分:1)

如果在文件列表为空时更改listFiles()实现,看起来异常消失。

package org.mule.transport.file;

import org.mule.api.MuleException;
import org.mule.api.construct.FlowConstruct;
import org.mule.api.endpoint.InboundEndpoint;
import org.mule.api.lifecycle.CreateException;
import org.mule.api.transport.Connector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class PatchedFileMessageReceiver extends FileMessageReceiver
{
    private static final Logger log = LoggerFactory.getLogger(PatchedFileMessageReceiver.class);

    /**
     *
     * @param connector
     * @param flowConstruct
     * @param endpoint
     * @param readDir
     * @param moveDir
     * @param moveToPattern
     * @param frequency
     * @throws CreateException
     */
    public PatchedFileMessageReceiver(Connector connector, FlowConstruct flowConstruct, InboundEndpoint endpoint, String readDir, String moveDir, String moveToPattern, long frequency) throws CreateException
    {
        super(connector, flowConstruct, endpoint, readDir, moveDir, moveToPattern, frequency);
    }

    /**
     *
     * @return
     * @throws MuleException
     */
    @Override
    List<File> listFiles() throws MuleException
    {
        List<File> list = super.listFiles();

        if(list.isEmpty()) {
            log.trace("List of files is empty, I'm gonna return a new empty ArrayList");
        }

        return ( list.isEmpty() ? new ArrayList<File>() : list );
    }
}

然后在文件连接器上设置自定义FileMessageReceiver,如下所示

<file:connector name="source-file-connector" autoDelete="false" fileAge="1000" pollingFrequency="1000" >
    <service-overrides messageReceiver="org.mule.transport.file.PatchedFileMessageReceiver" />
</file:connector>

这个东西应该在上游真正固定。作为用户,人们期望不必处理这类问题。

答案 1 :(得分:1)

看起来像一个问题,应该确实修复。我为你创建了issue。密切注意它,以了解修复的进展。

答案 2 :(得分:1)

比每次调用listFiles()(并且没有文件)时返回新列表更好的解决方案是在http://grepcode.com/file/repo1.maven.org/maven2/org.mule.transports/mule-transport-file/3.5.0/org/mule/transport/file/FileMessageReceiver.java#64使用CopyOnWriteArrayList for NO_FILES

private static final List<File> NO_FILES = new CopyOnWriteArrayList<File>();

这样您就可以避免实例创建。