我们大家都知道,每个运行中的线程都有一个成员contextClassLoader,用来在运行时动态地载入其它类。

系统默认的contextClassLoader是systemClassLoader,所以一般而言java程序在执行时可以使用JVM自带的类、$JAVA_HOME/jre/lib/ext/中的类和$CLASSPATH/中的类,对于非默认的jar,一般只能手动在配置环境添加。

但事实上,我们可以通过Thread.currentThread().setContextClassLoader()更改当前线程的contextClassLoader行为,实现在程序内加载外部jar。

PS:
ClassLoader的工作原理是:
1) 线程需要用到某个类时,contextClassLoader将被请求来载入该类
2) contextClassLoader请求它的父ClassLoader来完成该载入请求
3) 如果父ClassLoader无法载入类,则contextClassLoader试图自己来载入



通过ClassLoader调用外部jar包packageorg.loon.framework.jar;
通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
/***//**
通过ClassLoader调用外部jar包*<p>Title:LoonFramework</p>
通过ClassLoader调用外部jar包*<p>Description:JarLoader,用于jar包的外部操作</p>
通过ClassLoader调用外部jar包*<p>Copyright:Copyright(c)2007</p>
通过ClassLoader调用外部jar包*<p>Company:LoonFramework</p>
通过ClassLoader调用外部jar包*
@authorchenpeng
通过ClassLoader调用外部jar包*@email:[email protected]
通过ClassLoader调用外部jar包*
@version0.1
通过ClassLoader调用外部jar包
*/

通过ClassLoader调用外部jar包
importjava.io.BufferedInputStream;
通过ClassLoader调用外部jar包
importjava.io.ByteArrayInputStream;
通过ClassLoader调用外部jar包
importjava.io.ByteArrayOutputStream;
通过ClassLoader调用外部jar包
importjava.io.File;
通过ClassLoader调用外部jar包
importjava.io.FileInputStream;
通过ClassLoader调用外部jar包
importjava.io.FileNotFoundException;
通过ClassLoader调用外部jar包
importjava.io.IOException;
通过ClassLoader调用外部jar包
importjava.io.InputStream;
通过ClassLoader调用外部jar包
importjava.lang.reflect.Method;
通过ClassLoader调用外部jar包
importjava.net.MalformedURLException;
通过ClassLoader调用外部jar包
importjava.net.URL;
通过ClassLoader调用外部jar包
importjava.util.ArrayList;
通过ClassLoader调用外部jar包
importjava.util.HashMap;
通过ClassLoader调用外部jar包
importjava.util.Hashtable;
通过ClassLoader调用外部jar包
importjava.util.jar.JarEntry;
通过ClassLoader调用外部jar包
importjava.util.jar.JarInputStream;
通过ClassLoader调用外部jar包
importjava.util.jar.Manifest;
通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
publicclassJarLoaderextendsClassLoader...{
通过ClassLoader调用外部jar包
//资源缓存
通过ClassLoader调用外部jar包
publicstaticHashtableresources=newHashtable();
通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包
publicstaticJarLoaderloader=newJarLoader();
通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
publicstaticClassload(byte[]resource)throwsException...{
通过ClassLoader调用外部jar包
//主函数所在类全称
通过ClassLoader调用外部jar包
StringmainClassName="";
通过ClassLoader调用外部jar包
//class资源及实体缓存
通过ClassLoader调用外部jar包
ArrayListclassNames=newArrayList();
通过ClassLoader调用外部jar包ArrayListclassBuffers
=newArrayList();
通过ClassLoader调用外部jar包
//存储依赖类
通过ClassLoader调用外部jar包
HashMapdepends=newHashMap();
通过ClassLoader调用外部jar包
//将byte[]转为JarInputStream
通过ClassLoader调用外部jar包
JarInputStreamjar=newJarInputStream(newByteArrayInputStream(
通过ClassLoader调用外部jar包resource));
通过ClassLoader调用外部jar包Manifestmanifest
=jar.getManifest();
通过ClassLoader调用外部jar包
//当Main-Class被声明时,获得主函数所在类全称
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(manifest!=null)...{
通过ClassLoader调用外部jar包mainClassName
=manifest.getMainAttributes().getValue("Main-Class");
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
//依次获得对应JAR文件中封装的各个被压缩文件的JarEntry
通过ClassLoader调用外部jar包
JarEntryentry;
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
while((entry=jar.getNextJarEntry())!=null)...{
通过ClassLoader调用外部jar包
//当找到的entry为class时
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(entry.getName().toLowerCase().endsWith(".class"))...{
通过ClassLoader调用外部jar包
//将类路径转变为类全称
通过ClassLoader调用外部jar包
Stringname=entry.getName().substring(0,
通过ClassLoader调用外部jar包entry.getName().length()
-".class".length()).replace(
通过ClassLoader调用外部jar包
'/','.');
通过ClassLoader调用外部jar包
//加载该类
通过ClassLoader调用外部jar包
byte[]data=getResourceData(jar);
通过ClassLoader调用外部jar包
//缓存类名及数据
通过ClassLoader调用外部jar包
classNames.add(name);
通过ClassLoader调用外部jar包classBuffers.add(data);
通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
else...{
通过ClassLoader调用外部jar包
//非class结尾但开头字符为'/'时
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(entry.getName().charAt(0)=='/')...{
通过ClassLoader调用外部jar包resources.put(entry.getName(),getResourceData(jar));
通过ClassLoader调用外部jar包
//否则追加'/'后缓存
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
}
else...{
通过ClassLoader调用外部jar包resources.put(
"/"+entry.getName(),getResourceData(jar));
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
//当获得的main-class名不为空时
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
while(classNames.size()>0)...{
通过ClassLoader调用外部jar包
//获得类路径全长
通过ClassLoader调用外部jar包
intn=classNames.size();
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
for(inti=classNames.size()-1;i>=0;i--)...{
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
try...{
通过ClassLoader调用外部jar包
//查询指定类
通过ClassLoader调用外部jar包
loader.defineClass((String)classNames.get(i),
通过ClassLoader调用外部jar包(
byte[])classBuffers.get(i),0,
通过ClassLoader调用外部jar包((
byte[])classBuffers.get(i)).length);
通过ClassLoader调用外部jar包
//获得类名
通过ClassLoader调用外部jar包
StringpkName=(String)classNames.get(i);
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(pkName.lastIndexOf('.')>=0)...{
通过ClassLoader调用外部jar包pkName
=pkName
通过ClassLoader调用外部jar包.substring(
0,pkName.lastIndexOf('.'));
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(loader.getPackage(pkName)==null)...{
通过ClassLoader调用外部jar包loader.definePackage(pkName,
null,null,null,
通过ClassLoader调用外部jar包
null,null,null,null);
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
//查询后删除缓冲
通过ClassLoader调用外部jar包
classNames.remove(i);
通过ClassLoader调用外部jar包classBuffers.remove(i);
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
catch(NoClassDefFoundErrore)...{
通过ClassLoader调用外部jar包depends.put((String)classNames.get(i),e.getMessage()
通过ClassLoader调用外部jar包.replaceAll(
"/","."));
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
catch(UnsupportedClassVersionErrore)...{
通过ClassLoader调用外部jar包
//jre版本错误提示
通过ClassLoader调用外部jar包
thrownewUnsupportedClassVersionError(classNames.get(i)
通过ClassLoader调用外部jar包
+","+System.getProperty("java.vm.name")+""
通过ClassLoader调用外部jar包
+System.getProperty("java.vm.version")+")");
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(n==classNames.size())...{
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
for(inti=0;i<classNames.size();i++)...{
通过ClassLoader调用外部jar包System.err.println(
"NoClassDefFoundError:"
通过ClassLoader调用外部jar包
+classNames.get(i));
通过ClassLoader调用外部jar包StringclassName
=(String)classNames.get(i);
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
while(depends.containsKey(className))...{
通过ClassLoader调用外部jar包className
=(String)depends.get(className);
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
break;
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
try...{
通过ClassLoader调用外部jar包
//加载
通过ClassLoader调用外部jar包
Thread.currentThread().setContextClassLoader(loader);
通过ClassLoader调用外部jar包
//获得指定类,查找其他类方式相仿
通过ClassLoader调用外部jar包
returnClass.forName(mainClassName,true,loader);
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
catch(ClassNotFoundExceptione)...{
通过ClassLoader调用外部jar包StringclassName
=mainClassName;
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
while(depends.containsKey(className))...{
通过ClassLoader调用外部jar包className
=(String)depends.get(className);
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
thrownewClassNotFoundException(className);
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
/***//**
通过ClassLoader调用外部jar包*获得指定路径文件的byte[]形式
通过ClassLoader调用外部jar包*
@paramname
通过ClassLoader调用外部jar包*
@return
通过ClassLoader调用外部jar包
*/

通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
finalstaticpublicbyte[]getDataSource(Stringname)...{
通过ClassLoader调用外部jar包FileInputStreamfileInput;
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
try...{
通过ClassLoader调用外部jar包fileInput
=newFileInputStream(newFile(name));
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
catch(FileNotFoundExceptione)...{
通过ClassLoader调用外部jar包fileInput
=null;
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包BufferedInputStreambufferedInput
=newBufferedInputStream(fileInput);
通过ClassLoader调用外部jar包
returngetDataSource(bufferedInput);
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
/***//**
通过ClassLoader调用外部jar包*获得指定InputStream的byte[]形式
通过ClassLoader调用外部jar包*
@paramname
通过ClassLoader调用外部jar包*
@return
通过ClassLoader调用外部jar包
*/

通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
finalstaticpublicbyte[]getDataSource(InputStreamis)...{
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(is==null)...{
通过ClassLoader调用外部jar包
returnnull;
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包ByteArrayOutputStreambyteArrayOutputStream
=newByteArrayOutputStream();
通过ClassLoader调用外部jar包
byte[]arrayByte=null;
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
try...{
通过ClassLoader调用外部jar包
byte[]bytes=newbyte[8192];
通过ClassLoader调用外部jar包bytes
=newbyte[is.available()];
通过ClassLoader调用外部jar包
intread;
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
while((read=is.read(bytes))>=0)...{
通过ClassLoader调用外部jar包byteArrayOutputStream.write(bytes,
0,read);
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包arrayByte
=byteArrayOutputStream.toByteArray();
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
catch(IOExceptione)...{
通过ClassLoader调用外部jar包
returnnull;
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
finally...{
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
try...{
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(byteArrayOutputStream!=null)...{
通过ClassLoader调用外部jar包byteArrayOutputStream.close();
通过ClassLoader调用外部jar包byteArrayOutputStream
=null;
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(is!=null)...{
通过ClassLoader调用外部jar包is.close();
通过ClassLoader调用外部jar包is
=null;
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
catch(IOExceptione)...{
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
returnarrayByte;
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
/***//**
通过ClassLoader调用外部jar包*获得指定JarInputStream的byte[]形式
通过ClassLoader调用外部jar包*
@paramjar
通过ClassLoader调用外部jar包*
@return
通过ClassLoader调用外部jar包*
@throwsIOException
通过ClassLoader调用外部jar包
*/

通过ClassLoader调用外部jar包
finalstaticprivatebyte[]getResourceData(JarInputStreamjar)
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
throwsIOException...{
通过ClassLoader调用外部jar包ByteArrayOutputStreamdata
=newByteArrayOutputStream();
通过ClassLoader调用外部jar包
byte[]buffer=newbyte[8192];
通过ClassLoader调用外部jar包
intsize;
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
while(jar.available()>0)...{
通过ClassLoader调用外部jar包size
=jar.read(buffer);
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(size>0)...{
通过ClassLoader调用外部jar包data.write(buffer,
0,size);
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
returndata.toByteArray();
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
/***//**
通过ClassLoader调用外部jar包*重载的getResource,检查是否重复包含
通过ClassLoader调用外部jar包
*/

通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
publicURLgetResource(Stringname)...{
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(resources.containsKey("/"+name))...{
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
try...{
通过ClassLoader调用外部jar包
returnnewURL("file:///"+name);
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
catch(MalformedURLExceptione)...{
通过ClassLoader调用外部jar包e.printStackTrace();
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
returnsuper.getResource(name);
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
/***//**
通过ClassLoader调用外部jar包*执行指定class类
通过ClassLoader调用外部jar包*
@paramclz
通过ClassLoader调用外部jar包*
@parammethodName
通过ClassLoader调用外部jar包*
@paramargs
通过ClassLoader调用外部jar包
*/

通过ClassLoader调用外部jar包
publicstaticvoidcallVoidMethod(Classclz,StringmethodName,
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包String[]args)
...{
通过ClassLoader调用外部jar包Class[]arg
=newClass[1];
通过ClassLoader调用外部jar包arg[
0]=args.getClass();
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
try...{
通过ClassLoader调用外部jar包Methodmethod
=clz.getMethod(methodName,arg);
通过ClassLoader调用外部jar包Object[]inArg
=newObject[1];
通过ClassLoader调用外部jar包inArg[
0]=args;
通过ClassLoader调用外部jar包method.invoke(clz,inArg);
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
catch(Exceptione)...{
通过ClassLoader调用外部jar包System.err.println(e.getMessage());
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
/***//**
通过ClassLoader调用外部jar包*重载的getResourceAsStream,检查是否重复包含
通过ClassLoader调用外部jar包
*/

通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
publicInputStreamgetResourceAsStream(Stringname)...{
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(name.charAt(0)=='/')...{
通过ClassLoader调用外部jar包name
=name.substring(1);
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
if(resources.containsKey("/"+name))...{
通过ClassLoader调用外部jar包
returnnewByteArrayInputStream((byte[])resources.get("/"+name));
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
returnsuper.getResourceAsStream(name);
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包}


运行示例:

通过ClassLoader调用外部jar包packageorg.loon.framework.jar;
通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
/***//**
通过ClassLoader调用外部jar包*<p>
通过ClassLoader调用外部jar包*Title:LoonFramework
通过ClassLoader调用外部jar包*</p>
通过ClassLoader调用外部jar包*<p>
通过ClassLoader调用外部jar包*Description:从外部启动jar包
通过ClassLoader调用外部jar包*</p>
通过ClassLoader调用外部jar包*<p>
通过ClassLoader调用外部jar包*Copyright:Copyright(c)2007
通过ClassLoader调用外部jar包*</p>
通过ClassLoader调用外部jar包*<p>
通过ClassLoader调用外部jar包*Company:LoonFramework
通过ClassLoader调用外部jar包*</p>
通过ClassLoader调用外部jar包*
通过ClassLoader调用外部jar包*
@authorchenpeng
通过ClassLoader调用外部jar包*@email:[email protected]
通过ClassLoader调用外部jar包*
@version0.1
通过ClassLoader调用外部jar包
*/

通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
publicclassJarTest...{
通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
publicstaticvoidmain(String[]args)...{
通过ClassLoader调用外部jar包
//将jar包转为byte[]
通过ClassLoader调用外部jar包
byte[]resource=JarLoader.getDataSource("D:/fps_test.jar");
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
try...{
通过ClassLoader调用外部jar包
//通过byte[]获得主函数所在类
通过ClassLoader调用外部jar包
Classclz=JarLoader.load(resource);
通过ClassLoader调用外部jar包
//调用main函数
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包
JarLoader.callVoidMethod(clz,"main",newString[]...{""});
通过ClassLoader调用外部jar包通过ClassLoader调用外部jar包}
catch(Exceptione)...{
通过ClassLoader调用外部jar包e.getStackTrace();
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包
通过ClassLoader调用外部jar包}

通过ClassLoader调用外部jar包

这时即使指定jar包没有被我们添加到lib中,程序依旧被顺利启动了。

但是有个缺点,在没有优化的前提下,这种直接加载外部包的速度在jvm会有很大损耗。
通过ClassLoader调用外部jar包
我们可以看到,fps值降低到正常值的50%左右(此fps实例见我CSDN以前的文章),所以并不适合直接运用在需要复杂运算的jar中类调用上(当然,有兴趣的话,可以在代码中优化,我自己在项目中写的另一个例子速度明显比这个快)。但是对于运算量小的外部jar调用,还是很方便的。

相关文章:

  • 2021-07-20
  • 2021-11-09
  • 2022-01-28
  • 2022-01-03
  • 2021-07-25
  • 2022-01-06
  • 2021-07-23
  • 2021-12-05
猜你喜欢
  • 2022-12-23
  • 2021-08-25
  • 2021-06-05
  • 2021-09-01
  • 2021-09-10
相关资源
相似解决方案