【问题标题】:How to restrict the execution of runnable JAR that is executed independently and can be executed through web application.?如何限制独立执行并且可以通过Web应用程序执行的可运行JAR的执行。?
【发布时间】:2016-11-19 12:12:24
【问题描述】:
我有一个可运行的 JAR 文件,它计划使用 Timer 独立运行。
同样的 JAR 通过 web 应用程序执行(在 spring MVC 中开发)。
如果 jar 是通过计时器执行的,那么我必须限制 JAR 的执行,然后不允许通过 Web 应用程序执行。
注意:[我已经使用 processbuilder 来执行 JAR。]
【问题讨论】:
-
-
-
最好的解决方案可能是让您的应用程序使用可以返回所有正在运行的进程列表的操作系统工具。如果您在列表中找到应用程序的名称,则它已经在运行。您还可以使用信号量方法,例如在其中编写将您的应用程序的 PID 放入文件中,并(再次)使用操作系统工具来查找 PID 当前是否正在使用......但这可能更容易出错,实际上甚至需要更多的编码。仅供参考,请看这里:stackoverflow.com/questions/2318220/…
-
@mika 但该解决方案仅限于 jar 的范围和在同一台机器上运行的 webapp。如果您仍想在集群环境中执行此操作,则需要将文件写入NFS 位置。
标签:
java
spring-mvc
jar
processbuilder
【解决方案1】:
我认为您正在开发可许可的 jar 。
以我的拙见,对于这种 jar,最好嵌入数据库并在 Db 中保存执行时间和端口使用情况,并比较使用时间并对其进行限制。由于系统时间差异或防病毒资源或系统时间分配资源等原因,计时器方法并不安全。但是对于监控网络,您可以使用 WatchDog 应用程序来处理此类问题,
public class Watchdog implements Runnable {
private Vector observers = new Vector(1);
private long timeout = -1;
private volatile boolean stopped = false;
public static final String ERROR_INVALID_TIMEOUT = "timeout less than 1.";
/**
* Constructor for Watchdog.
* @param timeout the timeout to use in milliseconds (must be >= 1).
*/
public Watchdog(long timeout) {
if (timeout < 1) {
throw new IllegalArgumentException(ERROR_INVALID_TIMEOUT);
}
this.timeout = timeout;
}
public void addTimeoutObserver(TimeoutObserver to) {
observers.addElement(to);
}
public void removeTimeoutObserver(TimeoutObserver to) {
//no need to synchronize, as Vector is always synchronized
observers.removeElement(to);
}
protected final void fireTimeoutOccured() {
Enumeration e = observers.elements();
while (e.hasMoreElements()) {
((TimeoutObserver) e.nextElement()).timeoutOccured(this);
}
}
/**
* Start the watch dog.
*/
public synchronized void start() {
stopped = false;
Thread t = new Thread(this, "WATCHDOG");
t.setDaemon(true);
t.start();
}
/**
* Stop the watch dog.
*/
public synchronized void stop() {
stopped = true;
notifyAll();
}
public synchronized void run() {
final long until = System.currentTimeMillis() + timeout;
long now;
while (!stopped && until > (now = System.currentTimeMillis())) {
try {
wait(until - now);
Boolean SafeToContinue=CheckDbCountDay();
if(SafeToContinue)
ExecJarUsingStrategyPattern(new StrategyDoIt());
else ExecJarUsingStrategyPattern(new showMessage());
} catch (InterruptedException e) {
callBack("plz call support");
}
}
if (!stopped) {
fireTimeoutOccured();
}
}
}
【解决方案2】:
如果我理解正确,您有不同的虚拟机执行相同的 jar/代码(我将其称为 operation)。如果是这样,您可以设置一个独立于这些 VM 的锁定机制。例如,您可以使用一个文件,但最好使用数据库及其本机锁定功能:创建一个“锁定”(ID、版本、操作、到期)表,然后每次执行操作时尝试检索该操作的锁定行,如果行不存在或已过期然后创建/更新锁定行设置过期并允许操作,否则抛出无法执行自锁定异常。过期用于避免在操作崩溃时永远锁定,因为无法执行finally(例如:操作系统崩溃)。为避免双重/并发写入,您应该对 Lock 表使用 DB optimistic locking 功能,例如:版本字段。在删除行的操作结束时释放锁。锁定行必须在不同的事务中创建和删除,与操作(如果有)分开
【解决方案3】:
最好的方法是使用数据库。
在应用程序开始时锁定特定行(使用 for update 以确保安全,以防两者同时启动)并在某列中写入 in_use 。
然后你做生意,一旦完成将同一行从 in_use 更新为 completed 。这样,在您的 jar 的一个实例上的特定时间将执行您的业务代码。如果两者都在不同的机器上,它也不会失败。
【解决方案4】:
您可以检查文件是否存在以表明 .jar 正在执行,如果是则终止:
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
if (FileLock.exists()){
System.out.println("The file exists so the jar is running");
System.exit(0);
}
FileLock.createLockFile();
//start Running the .Jar File
/*
*
*
* CODE
*
*
*
*/
//Delete the file when the program terminates
FileLock.deleteLockFile();
System.out.println("Program exiting normally");
}
}
class FileLock {
private static File lock = new File("jar-running.txt");
public static boolean exists()
{
return lock.exists();
}
public static void createLockFile()
{
try {
lock.createNewFile();
} catch (IOException e) {
// the file already exists
System.exit(0);}
}
public static void deleteLockFile()
{
if(lock.exists()) lock.delete();
}
}
【解决方案5】:
基本上你需要的是一个可以跨 jvm 工作的锁。或者,可以说,一种在 jvm 之间共享对象的方法,以便您可以锁定它们。这里有多种可用的解决方案,比如创建一个文件来指示一个锁,或者如果您的应用程序中已经有一个数据库,则创建一个基于数据库的锁,或者一个分发锁。 Terracotta 是一种可能的解决方案。你也可以试试apache zookeeper,curator 库,同样来自 apache,它非常易于使用。
动物园管理员和馆长:代码看起来很简单:
lock = new InterProcessSemaphoreMutex(client, lockPath);
lock.acquire(5, TimeUnit.MINUTES);
// do something
lock.release();
完整示例:here