Java 运行新鲜jar文件时openjdk出现致命错误

Java 运行新鲜jar文件时openjdk出现致命错误,java,openjdk,Java,Openjdk,我想实现一个ApplicationChangeMonitor,它监视文件系统中当前执行的jar文件中的更改。当检测到更改时,应用程序应重新启动。我正在使用一个测试来检测变化 设置: 在(Windows)Eclipse中开发samba共享上的工作区(Linux系统) jar文件由Eclipse maven(m2e)在该samba共享上生成 jar文件在Linux系统上从shell执行(使用openjdk) 因此,每次创建新的jar文件时,都应该在Linux系统上重新启动正在运行的应用程序。首先

我想实现一个
ApplicationChangeMonitor
,它监视文件系统中当前执行的jar文件中的更改。当检测到更改时,应用程序应重新启动。我正在使用一个测试来检测变化

设置:

  • 在(Windows)Eclipse中开发samba共享上的工作区(Linux系统)
  • jar文件由Eclipse maven(m2e)在该samba共享上生成
  • jar文件在Linux系统上从shell执行(使用openjdk)
因此,每次创建新的jar文件时,都应该在Linux系统上重新启动正在运行的应用程序。首先,我尝试让应用程序自行重启,但大多数时候,我都会遇到来自JVM的致命错误。然后我选择了一种更简单的方法:我只是在检测到更改后让应用程序自行结束,并用bash实现了重启机制:

while true ; do java -jar application.jar ; done
奇怪的是,在应用程序更改后,我仍然会出现一两次致命错误。例如:


  • java-jar application.jar这是因为在将新文件写入磁盘时,您会收到新文件的通知。这对于WatchService来说是一件坏事,它会在创建新文件但尚未完全写入磁盘时通知您

    当新的jar文件被写入磁盘时,jar文件被进程锁定,进程将jar文件写入磁盘。在文件创建者进程未解锁文件之前,您无法访问文件

    解决方法是:您必须尝试打开文件,如果文件被打开,则文件已完全写入磁盘。若无法打开文件,请等待一段时间(或者不要等待,请尝试下一步),然后尝试下一步打开文件

    要解锁文件,请实现如下操作:

    public void unlockFile(String jarFileName){
        FileInputStream fis = null;
        while(true){
            try{
                // try to open file
                fis = new FileInputStream(jarFileName);
                // you succeed to open file
                // return
                // file will be closed in finally block, as it will always executed
                return;
            }catch(Exception e){
                // file is still locked
                // you may sleep for sometime to let other process finish with file and
                // file gets unlocked
    
                // if you dont have problem with this process utilizing CPU, dont sleep!
                try{
                    Thread.sleep(100);
                }catch(InterruptedException ie){
                }
            }finally{
                if(fis != null){
                    try{
                        fis.close();
                    }catch(Exception e){
                    }
                }
            }
        }
    
    void shutDownMethod(){
        // get file name from watcher, below line will depend on your logic and code.
        String jarFileName = watcherThread.getNewNotifiedFile();
        // unlock new jar file.
        unlockFile(jarFileName);
        // shutdown JVM
        System.exit(0);
        // bash will restart JVM
    }
    
    解决您的问题,

    您告诉我:“我只是在检测到更改并用bash实现重启机制后让应用程序自行结束”

    所以,在结束java过程之前,按照我在上述方法中的建议解锁文件。我相信错误会消失的。试着让我知道结果

    大概是这样的:

    public void unlockFile(String jarFileName){
        FileInputStream fis = null;
        while(true){
            try{
                // try to open file
                fis = new FileInputStream(jarFileName);
                // you succeed to open file
                // return
                // file will be closed in finally block, as it will always executed
                return;
            }catch(Exception e){
                // file is still locked
                // you may sleep for sometime to let other process finish with file and
                // file gets unlocked
    
                // if you dont have problem with this process utilizing CPU, dont sleep!
                try{
                    Thread.sleep(100);
                }catch(InterruptedException ie){
                }
            }finally{
                if(fis != null){
                    try{
                        fis.close();
                    }catch(Exception e){
                    }
                }
            }
        }
    
    void shutDownMethod(){
        // get file name from watcher, below line will depend on your logic and code.
        String jarFileName = watcherThread.getNewNotifiedFile();
        // unlock new jar file.
        unlockFile(jarFileName);
        // shutdown JVM
        System.exit(0);
        // bash will restart JVM
    }
    

    我就是这么想的(见最后一段)。但是(1)在最后一次更改后500毫秒的延迟后,我缓冲更改并采取措施(因此,
    WatchService
    不再提供任何更改事件),(2)为什么md5sum会打印相同的sum(无论它是否工作),(3)java不会给出“无效或损坏的jarfile”之类的错误,而不是致命的退出?[我实现了(1),因为进程实际上可以获取锁,但Eclipse给出了错误消息。可能这些现象是由于samba的具体情况造成的。]我真的没有得到您正在尝试的,您在哪个进程中检查校验和?您得到的校验和是正确的,因为这不是java进程!看最后一行:我在bash中计算校验和,在应用程序结束后和重新启动之前。现在,在第一次或两次尝试之后,通常会出现致命的错误,之后jar就可以正常运行了。jar的所有三次校验和都相同,都是从shell计算的,在运行jar=>之前,文件必须全部完成!如果jar没有完全写入,我会得到(
    错误:无效或损坏的jarfile
    )。如果是这样的话,我有时无法实例化SLF4J LoggerFactory(
    java.lang.NoClassDefFoundError:ch/qos/logback/core/joran/spi/JoranException
    ),有时会丢失不同的类,有时会出现致命错误(
    java运行时环境检测到致命错误:
    )。等待几秒钟后,我可以毫无问题地运行应用程序。您是否按照我的回答尝试在解锁文件后退出Java?并从bash循环中删除检查校验和,然后按照我的回答进行尝试。对于您的问题:“首先,我尝试使应用程序自行重新启动”您是如何重新启动java进程本身的?如果您使用其他java进程来重新启动此java进程,我将为您提供另一个解决方案!
    void shutDownMethod(){
        // get file name from watcher, below line will depend on your logic and code.
        String jarFileName = watcherThread.getNewNotifiedFile();
        // unlock new jar file.
        unlockFile(jarFileName);
        // shutdown JVM
        System.exit(0);
        // bash will restart JVM
    }