简体   繁体   English

从另一个罐子里运行一个罐子

[英]Running a jar from within another jar

Re-writing this for clarity before I bounty it: 在我获得奖励之前,为了清晰起见重写这个:

What I want to do is make a bootstrap loader for a program that is already made in (executable)jar form. 我想要做的是为已经以(可执行的)jar形式制作的程序创建一个bootstrap加载器。 This bootstrap program would have three simple goals during it's runtime: 这个引导程序在运行时会有三个简单的目标:

  1. Compare a local xml file for the target program to one that's hosted on a server (to make sure that they are the same version) 将目标程序的本地xml文件与托管在服务器上的文件进行比较(以确保它们是相同的版本)

  2. If they are not the same version, and the online version is newer, download the newer version. 如果它们不是同一版本,并且在线版本较新,请下载较新版本。

  3. Re-write the xml file to reflect this change. 重写xml文件以反映此更改。

  4. Execute the second jar file (launch it as though you launched the executable). 执行第二个jar文件(就像启动可执行文件一样启动它)。

The issue I'm having is with step number 4. I have found myself struggling to find a solid way to launch a jar from within my bootstrap program despite looking at UrlClassLoader and other libraries. 我遇到的问题是第4步。尽管我在查看UrlClassLoader和其他库,但我发现自己很难找到一种从我的引导程序中启动jar的可靠方法。

Due to some outside issues, JNLP / Web-start is not an option for this case. 由于一些外部问题,JNLP / Web-start不适用于此案例。

TL;DR: I need to find a way to download / launch a jar from within a jar in order to update a program at the time the bootstrap is run. TL; DR:我需要找到一种从jar中下载/启动jar的方法,以便在运行bootstrap时更新程序。

Thanks! 谢谢!

Runtime.getRuntime().exec() 调用Runtime.getRuntime()。EXEC()

There are some pitfalls here though if your MyApp.jar will have any output. 如果你的MyApp.jar有任何输出,那么这里有一些陷阱。

Check the docs for details of how to properly use exec... 检查文档以获取有关如何正确使用exec的详细信息...

http://docs.oracle.com/javase/6/docs/api/java/lang/Process.html http://docs.oracle.com/javase/6/docs/api/java/lang/Process.html

And see this SO post about some of the pitfalls... 关于一些陷阱,请看这篇SO帖子......

Java Runtime.exec() Java Runtime.exec()

When you say 'executing the new jar', do you mean starting a standalone application? 当你说'执行新jar'时,你的意思是启动一个独立的应用程序吗? One possibility could be to simply execute a new Java process from the Updater.jar bootstrap logic and then Exit itself. 一种可能性是简单地从Updater.jar引导逻辑执行新的Java进程,然后退出自身。

By other words you want to implement self-updatable application. 换句话说,您希望实现自我更新的应用程序。 It is possible and even not so difficult. 这是可能的,甚至不是那么困难。

Your program should be designed to have 2 parts. 您的程序应该设计为2部分。 The loader (and updater) and the business logic. 加载器(和更新程序)和业务逻辑。 Loader should start business logic using separate class loader. Loader应该使用单独的类加载器启动业务逻辑。 You can use UrlClassLoader . 您可以使用UrlClassLoader The loader will go to the online service and check version. 加载程序将转到在线服务并检查版本。 If it is needed it will create URLConnection , download the new jar and store it somewhere in the filesytem (eg in user home directory). 如果需要,它将创建URLConnection ,下载新jar并将其存储在filesytem中的某个位置(例如,在用户主目录中)。 Then it will run the business logic using the already mentioned class loader that loads classes from just downloaded jar file. 然后它将使用已经提到的类加载器运行业务逻辑,该加载器从刚刚下载的jar文件加载类。

This actually mimics the JNLP behavior. 这实际上模仿了JNLP的行为。

I hate having to answer my own question, but in this case I feel like it needs to be done... 我不想回答我自己的问题,但在这种情况下我觉得需要做...

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import org.w3c.dom.Document;


public class updater {
public static void main(String[] args) throws IOException {
    try{
        DefaultHttpClient httpclient = ClientMaker();
        HttpGet get = new HttpGet("http://encorpops04:8080/Updater-test/Version.xml");
        HttpResponse response = httpclient.execute(get);
        InputStream in = response.getEntity().getContent();

        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = domFactory.newDocumentBuilder();
        Document doc = builder.parse(in);

        //Parse the Xml.
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = xpath.compile("//version/number/text()");
        String result = (String) expr.evaluate(doc, XPathConstants.STRING);
        System.out.println(result);

        File f = new File(System.getProperty("user.dir")+ "\\Version.xml");
        in = new FileInputStream(f) ;
        doc = builder.parse(in);
        expr=xpath.compile("//version/number/text()");
        String result2 = (String) expr.evaluate(doc, XPathConstants.STRING);
        System.out.println(result2);


        if(Double.parseDouble(result2) < Double.parseDouble(result)){
            HttpGet get2 = new HttpGet("http://encorpops04:8080/Updater-test/MyOutput.jar"); 
            HttpResponse response2 = httpclient.execute(get2);
            InputStream in2 = response2.getEntity().getContent();
            File f2 = new File("MyOutput.jar");
            OutputStream fos = new FileOutputStream(f2);
            byte buf[] = new byte[1024];
            int len;
            while ((len = in2.read(buf)) > 0) {
                fos.write(buf, 0, len);
            }
            fos.close();
            in.close();
        }
        System.out.println("cmd.exe /C  javaw -jar"  +System.getProperty("user.dir") + "\\MyOutput.jar");
        Process p = Runtime.getRuntime().exec("cmd.exe /C  javaw -jar "  +System.getProperty("user.dir") + "\\MyOutput.jar");
        p.waitFor();
        p.destroy();
    }catch(Exception e){ e.printStackTrace(); }


}

public static DefaultHttpClient ClientMaker() {
    int connectiontimeout = 30000; // 1 second int sockettimeout = 1000;
    HttpParams httpparameters = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(httpparameters,
            connectiontimeout);
    HttpConnectionParams.setSoTimeout(httpparameters, connectiontimeout);
    DefaultHttpClient httpclient = new DefaultHttpClient(httpparameters);
    return httpclient;
}

}

Version.xml looks like this: Version.xml如下所示:

<?xml version="1.0" encoding="ISO-8859-1"?>
<version>
    <number>1.0</number>
</version>

Sidenote- I didn't make version.xml update automatically, you can either edit the number in there to match, or just pull the one that you check against to replace it. Sidenote-我没有自动更新version.xml,你可以编辑那里的数字来匹配,或者只是拉你检查的那个来替换它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM