java -jar myapp.war
可是,大家都知道WAR file與JAR file結構不同,要達到這個目的就得先知道MANIFEST的結構;例如,指定一個main class:
Manifest-Version: ... Ant-Version: ... Created-By: ... Main-Class: Main
但WAR file中,class不是在WEB-INF/classes中,就是在WEB-INF/lib中;所以還需指定 classpath:
... Class-Path: WEB-INF/classes ...
多半按上述方法完成後,如同這篇說明一樣,測試的結果會是:
java.lang.NoClassDefFoundError
顯然,Class-Path不是這樣子用的。
不過,該說明的解答中提到,可以模仿Hudson.war一般:自製main class。另外,因為WAR file無異於其他的ZIP file,於是請教了谷歌大神之後,找到這篇教如何自ZIP或JAR file中載入class。
最後就完成了我的需求「即是WAR file,又可以執行某一class」:
java -jar myapp.war "some-parameter-for-launching-SomeUtil"
程式如下:
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import my.util.SomeUtil; public class Main extends ClassLoader { private static final String DELEGATE = "my.util.SomeUtil"; private final ZipFile file; public Main(String filename) throws IOException { this.file = new ZipFile(filename); } @Override public Class findClass(String name) throws ClassNotFoundException { ZipEntry entry = this.file.getEntry( (this.file.getName().endsWith("war") ? "WEB-INF/classes/" : "") + name.replace(".", "/") + ".class" ); if (entry == null) { throw new ClassNotFoundException(name); } try { byte[] array = new byte[1024]; InputStream ins = this.file.getInputStream(entry); ByteArrayOutputStream out = new ByteArrayOutputStream(array.length); int length = ins.read(array); while (length > 0) { out.write(array, 0, length); length = ins.read(array); } return defineClass(name, out.toByteArray(), 0, out.size()); } catch (IOException exception) { throw new ClassNotFoundException(name, exception); } } /** * @param args */ public static void main(String[] args) { if(args != null) { try { Main classLoader = new Main(args[0]); classLoader.findClass(DELEGATE); System.out.println(SomeUtil.doSomething(args[1])); } catch (Exception e) { e.printStackTrace(); } } } }
不過,這個Main class記得要包在WAR file中的根目錄下。
沒有留言:
張貼留言