编写自己的Wrapper Class
A URL Connection to a Java ARchive (JAR) file or an entry in a JAR file.
The syntax of a JAR URL is:
jar:<url>!/{entry}
参考: java.net.JarURLConnection
http://java.sun.com/j2se/1.4.2/docs/api/java/net/JarURLConnection.html
目的:要解决在可执行Jar文件中使用包含在其他地方的Jar文件中的class.
初级方法:使用Java extension机制,通过编写启动脚本来解决问题:
把第三方的Jar Library复制到{java home}\jre\lib\ext 目录下
或使用java ?Xbootclasspath 命令行参数:
-Xbootclasspath:<directories and zip/jar files separated by ;>
set search path for bootstrap classes and resources
-Xbootclasspath/a:<directories and zip/jar files separated by ;>
append to end of bootstrap class path
-Xbootclasspath/p:<directories and zip/jar files separated by ;>
大多数的Java 应用服务器都使用了制作启动脚本的方法.
例子: 脚本run.bat 可以参看Jboss Application的run.bat或run.sh脚本
中级方法: 利用Jar 扩展机制规范,通过制作安装包来解决问题.
利用Jar包扩展(extension)机制通过Manifest Specification 来编写
参考: http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html
利用META-INF/MANIFEST.MF文件中的Class-Path:来指定需要引用的第三包,
将需要的第三方包放到在Class-Path:指定的目录下,然后把主程序jar包和第三包
制作安装包,在安装的时候按照目录结构安装。然后SystemClassLoader(sun.misc.Launcher)
自动加载
高级方法,编写自己的Container类或bootStrap Wrapper类.
思路:实现一个Custom ClassLoader-系统类java.开头的类让SysemClassLoader来载入,
其他的类用CustomClassLoader读取给出的Jar Library 包来实现.
最终实现 Class.forName(String name)自动使用Custom ClassLoader来寻找和加载class.
这里需要介绍一些Java ClassLoader的一些限制的知识,ClassLoader的详细原理,可以参看
其他相关介绍.
Hack Java:
强行设置系统默认的ClassLoader,有作用吗?No
Field tclass = ClassLoader.class.getDeclaredField("scl");
tclass.setAccessible(true);
tclass.set(null,Mydefault);
JVM的 SystemClassLoader是 sun.misc.Luncher的实例,这里面包含native的本地方法,
其中工作算法不得而之,JVM唯一给我们留下的扩展机制就是改变ContextClassLoader来实现
JVM的ClassLoader委托模式(delegation mode).
详细介绍:
Custom ClassLoader代码
/**
* Don't Reinvent wheel
* 使用 URLClassLoader 来载入Jar Library
*
*/
import java.io.InputStream;
import java.io.File;
import java.net.URLClassLoader;
import java.util.*;
import java.net.URL;
public class myClassLoaderByURL extends java.lang.ClassLoader
{
static java.net.URL _url=null;
static String libpath=null;
public static myClassLoaderByURL defaultld=null;
public myClassLoaderByURL(String liburl,ClassLoader parent) throws Exception
{
super(parent);
if(!checkJar(liburl))
{
throw new java.lang.RuntimeException("Jar File "+liburl+" not exist");
}
try
{
_url = new URL("jar:file:/"+liburl+"!/");
}catch(Exception e)
{
e.printStackTrace();
}
}
protected Class findClass(String name) throws ClassNotFoundException
{
Class speClass=null;
try
{
speClass = getParent().loadClass(name );
System.out.println("myClassLoaderByURL Msg: parent CLD find Class............"+name);
} catch( ClassNotFoundException cnfe )
{
try
{
String rname = name;
rname = rname.replace ('.', '/') + ".class";//重要,必须还原为目录格式
System.out.println("myClassLoaderByURL Msg: Option jar Lib:"+_url.toExternalForm());
System.out.println("myClassLoaderByURL Msg: find class name:"+rname);
URLClassLoader ucld = new URLClassLoader(new URL[]{_url},myClassLoaderByURL.class.getClassLoader());
InputStream is = ucld.getResourceAsStream(rname);
if(is==null)
{
throw new ClassNotFoundException(" Can't Find Specified Class:"+name);
}
int size=is.available();
byte[] b = new byte[size];
is.read(b,0,size);
is.close();
speClass = defineClass(name,b,0,b.length);
}catch(Exception ioe)
{
ioe.printStackTrace();
throw new ClassNotFoundException();
}
}catch(Exception ce)
{
ce.printStackTrace();
throw new ClassNotFoundException();
}
System.out.println("myClassLoaderByURL Msg: ok,load success");
return speClass;
}
public Class loadClass( String pClassName, boolean pResolve ) throws ClassNotFoundException {
System.out.println("myClassLoaderByURL Msg:loadClass(), resolve: " + pResolve );
Class lClass = findLoadedClass( pClassName );
lClass = findClass( pClassName );
//ResolveClass.
try {
if( pResolve ) {
System.out.println("myClassLoaderByURL Msg:resolve class: " + lClass );
resolveClass( lClass );
}
} catch (Error e) {
e.printStackTrace();
throw e;
}
return lClass;
}
public Class loadClass( String pClassName) throws ClassNotFoundException
{
Class t =loadClass(pClassName,true);
return t;
}
private boolean checkJar(String jarfile)
{
System.out.println("myClassLoaderByURL Msg: checkJar:"+jarfile);
File jarf = new File(jarfile);
try
{
System.out.println(jarf.getCanonicalFile());
}catch(Exception ee)
{
}
return jarf.exists();
}
}
编写自己的Boot Wrapper类:
import java.io.*;
import java.util.zip.*;
import java.util.jar.*;
import java.net.URLClassLoader;
import java.net.URL;
import java.lang.reflect.Method;
public class testClassLoaderByURL extends java.lang.Thread
{
static myClassLoaderByURL Mydefault;
static String JarLibraryPath="";
static String executedClass = "";
public static void main(String[] args) throws Exception
{
if(args.length <2)
{
System.out.println("Syntax testClassLoaderByURL /path/xx.jar Executable class name(include main method");
System.out.println("Example: java testClassLoaderByURL c:\\temp\\test.jar org.sun.go");
System.exit(0);
}
JarLibraryPath=args[0];
executedClass = args[1];
//here can verified parameter
System.out.println("Jar is:"+JarLibraryPath+", Class is:"+executedClass);
System.out.println("Begin Load");
Mydefault = new myClassLoaderByURL(JarLibraryPath,testClassLoader.class.getClassLoader());
myClassLoaderByURL.defaultld = Mydefault;
Thread.currentThread().setContextClassLoader(Mydefault);
Class cls = Mydefault.loadClass(executedClass);//重要.
Method main = cls.getMethod("main", new Class[]{String[].class});
main.invoke(cls, new Object[]{args});
}
}