如何在Spring批量集成中使用文件锁?

时间:2016-05-10 23:24:53

标签: spring spring-integration spring-batch

在我的spring-batch-integration应用程序中,文件轮询调用每个文件的batchjob,这个应用程序可以在多个服务器(节点)上运行,但它们都应该读取一个公共目录。现在,我写了一个自定义的锁定器,对文件进行锁定,以便任何其他实例都无法处理同一文件。代码如下

public class MyFileLocker extends AbstractFileLockerFilter{

private final ConcurrentMap<File, FileLock> lockCache = new ConcurrentHashMap<File, FileLock>();
private final ConcurrentMap<File, FileChannel> ChannelCache = new ConcurrentHashMap<File, FileChannel>();

@Override
public boolean lock(File fileToLock) {
    FileChannel channel;
    FileLock lock;
    try {
        channel = new RandomAccessFile(fileToLock, "rw").getChannel();
        lock = channel.tryLock();

        if (lock == null || !lock.isValid()) {  
            System.out.println(" Problem in acquiring lock!!" + fileToLock);
            return false;
        }
        lockCache.put(fileToLock, lock);
        ChannelCache.put(fileToLock, channel);

    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return true;
}

@Override
public boolean isLockable(File file) {

    return file.canWrite();
}

@Override
public void unlock(File fileToUnlock) {
    FileLock lock = lockCache.get(fileToUnlock);
    try {
    if(lock!=null){
        lock.release();
        ChannelCache.get(fileToUnlock).close();
    }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

}

现在,当我调用我的Spring批处理并尝试使用flatfileitemreader读取该文件时,它给了我

  

org.springframework.batch.item.file.NonTransientFlatFileException

我相信即将到来的beacuse文件被锁定。我做了一些谷歌搜索,发现NIOLocker以一种即使当前线程无法读取它的方式锁定文件。我找到了一个link,它显示了如何读取锁定的文件,但它们正在使用缓冲区。 如何使我的文件可以访问我的FlatfileItemReader。

请建议。

3 个答案:

答案 0 :(得分:2)

是的,您真的只能通过ByteBuffer

访问锁定的文件内容
FileChannel fileChannel = channelCache.get(lockedFile);
ByteBuffer byteBuffer = ByteBuffer.allocate((int) fileChannel.size());
fileChannel.read(byteBuffer);
System.out.println("Read File " + lockedFile.getName() + " with content: " + new String(byteBuffer.array()));

哦!是啊。你真的指着我的回购: - )。

因此,对于locker,除非在byte[]之前复制/粘贴文件FlatfileItemReader,或者只是将一些自定义BufferedReaderFactory注入其中,否则您无法选择相同的FlatfileItemReader,将锁定的文件转换为相应的BufferedReader

new BufferedReader(new CharArrayReader(byteBuffer.asCharBuffer().array()));

答案 1 :(得分:1)

根据您分享的link,看起来您可以尝试以下操作。

//This is from your link (except the size variable)
FileChannel fileChannel = channelCache.get(lockedFile);
int size = (int) fileChannel.size();
ByteBuffer byteBuffer = ByteBuffer.allocate(size);
fileChannel.read(byteBuffer);

//Additional code that you could try
byte[] bArray = new byte[size];

//Write data to the byte array
byteBuffer.get(bArray);

FlatFileItemReader flatFileItemReader = new FlatFileItemReader();
flatFileItemReader.setResource(new ByteArrayResource(bArray));

//Next you can try reading from your flatFileItemReader as usual
...

如果不能解决您的问题,请告诉我。

答案 2 :(得分:0)

解决方案:我正在创建一个包含锁定文件内容并进行处理的临时文件。处理完成后,我将该文件存档并删除锁定的和临时的两个文件。这里的关键是创建一个具有锁定文件内容的新文件。以下代码如下:


File tmpFile = new File(inputFile.getAbsolutePath() + ".lck");     
FileChannel fileChannel = MyFileLocker.getChannelCache().get(new File(inputFile.getAbsolutePath()));
InputStream inputStream = Channels.newInputStream(fileChannel);
ByteStreams.copy(inputStream, Files.newOutputStreamSupplier(tmpFile));


这里inputFile是我的锁定文件,tmp文件是具有锁定文件内容的新文件。我还在我的更衣室类中创建了一个方法来解锁和删除

    public void unlockAndDelete(File fileToUnlockandDelete) {
    FileLock lock = lockCache.get(fileToUnlockandDelete);
    String fileName = fileToUnlockandDelete.getName();
    try {
    if(lock!=null){
        lock.release();
        channelCache.get(fileToUnlockandDelete).close();
        //remove from cache
        lockCache.remove(fileToUnlockandDelete);
        channelCache.remove(fileToUnlockandDelete);
        boolean isFiledeleted = fileToUnlockandDelete.delete();
        if(isFiledeleted){
            System.out.println("File deleted successfully" + fileName);
        }else{
            System.out.println("File is not deleted."+fileName);
        }
    }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}