通过ClassLoader调用外部jar包

通过ClassLoader调用外部jar包

我们大家都知道,每个运行中的线程都有一个成员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试图自己来载入



package org.loon.framework.jar;

/** *//**
 * <p>Title: LoonFramework</p>
 * <p>Description:JarLoader,用于jar包的外部操作</p>
 * <p>Copyright: Copyright (c) 2007</p>
 * <p>Company: LoonFramework</p>
 * 
@author chenpeng  
 * @email:ceponline@yahoo.com.cn 
 * 
@version 0.1
 
*/

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;

public class JarLoader extends ClassLoader ...{
    
//资源缓存
    public static Hashtable resources = new Hashtable();
 
    
public static JarLoader loader = new JarLoader();

    
public static Class load(byte[] resource) throws Exception ...{
        
// 主函数所在类全称
        String mainClassName = "";
        
//class资源及实体缓存
        ArrayList classNames = new ArrayList();
        ArrayList classBuffers 
= new ArrayList();
        
// 存储依赖类
        HashMap depends = new HashMap();
        
// 将byte[]转为JarInputStream
        JarInputStream jar = new JarInputStream(new ByteArrayInputStream(
                resource));
        Manifest manifest 
= jar.getManifest();
        
// 当Main-Class被声明时,获得主函数所在类全称
        if (manifest != null...{
            mainClassName 
= manifest.getMainAttributes().getValue("Main-Class");
        }

        
// 依次获得对应JAR文件中封装的各个被压缩文件的JarEntry
        JarEntry entry;
        
while ((entry = jar.getNextJarEntry()) != null...{
            
// 当找到的entry为class时
            if (entry.getName().toLowerCase().endsWith(".class")) ...{
                
// 将类路径转变为类全称
                String name = entry.getName().substring(0,
                        entry.getName().length() 
- ".class".length()).replace(
                        
'/''.');
                
// 加载该类
                byte[] data = getResourceData(jar);
                
// 缓存类名及数据
                classNames.add(name);
                classBuffers.add(data);

            }
 else ...{
                
// 非class结尾但开头字符为'/'时
                if (entry.getName().charAt(0== '/'...{
                    resources.put(entry.getName(), getResourceData(jar));
                
// 否则追加'/'后缓存    
                }
 else ...{
                    resources.put(
"/" + entry.getName(), getResourceData(jar));
                }

            }

        }

        
//当获得的main-class名不为空时
        while (classNames.size() > 0...{
            
//获得类路径全长
            int n = classNames.size();
            
for (int i = classNames.size() - 1; i >= 0; i--...{
                
try ...{
                    
//查询指定类
                    loader.defineClass((String) classNames.get(i),
                            (
byte[]) classBuffers.get(i), 0,
                            ((
byte[]) classBuffers.get(i)).length);
                    
//获得类名
                    String pkName = (String) classNames.get(i);
                    
if (pkName.lastIndexOf('.'>= 0...{
                        pkName 
= pkName
                                .substring(
0, pkName.lastIndexOf('.'));
                        
if (loader.getPackage(pkName) == null...{
                            loader.definePackage(pkName, 
nullnullnull,
                                    
nullnullnullnull);
                        }

                    }

                    
//查询后删除缓冲
                    classNames.remove(i);
                    classBuffers.remove(i);
                }
 catch (NoClassDefFoundError e) ...{
                    depends.put((String) classNames.get(i), e.getMessage()
                            .replaceAll(
"/""."));
                }
 catch (UnsupportedClassVersionError e) ...{
                    
//jre版本错误提示
                    throw new UnsupportedClassVersionError(classNames.get(i)
                            
+ "" + System.getProperty("java.vm.name"+ " "
                            
+ System.getProperty("java.vm.version"+ ")");
                }

            }

            
if (n == classNames.size()) ...{
                
for (int i = 0; i < classNames.size(); i++...{
                    System.err.println(
"NoClassDefFoundError:"
                            
+ classNames.get(i));
                    String className 
= (String) classNames.get(i);
                    
while (depends.containsKey(className)) ...{
                        className 
= (String) depends.get(className);
                    }

                }

                
break;
            }

        }

        
try ...{
            
//加载
            Thread.currentThread().setContextClassLoader(loader);
            
// 获得指定类,查找其他类方式相仿
            return Class.forName(mainClassName, true, loader);
        }
 catch (ClassNotFoundException e) ...{
            String className 
= mainClassName;
            
while (depends.containsKey(className)) ...{
                className 
= (String) depends.get(className);
            }

            
throw new ClassNotFoundException(className);
        }

    }


    
/** *//**
     * 获得指定路径文件的byte[]形式
     * 
@param name
     * 
@return
     
*/

    
final static public byte[] getDataSource(String name) ...{
        FileInputStream fileInput;
        
try ...{
            fileInput 
= new FileInputStream(new File(name));
        }
 catch (FileNotFoundException e) ...{
            fileInput 
= null;
        }

        BufferedInputStream bufferedInput 
= new BufferedInputStream(fileInput);
        
return getDataSource(bufferedInput);
    }

    
    
/** *//**
     * 获得指定InputStream的byte[]形式
     * 
@param name
     * 
@return
     
*/

    
final static public byte[] getDataSource(InputStream is) ...{
        
if (is == null...{
            
return null;
        }

        ByteArrayOutputStream byteArrayOutputStream 
= new ByteArrayOutputStream();
        
byte[] arrayByte = null;
        
try ...{
            
byte[] bytes = new byte[8192];
            bytes 
= new byte[is.available()];
            
int read;
            
while ((read = is.read(bytes)) >= 0...{
                byteArrayOutputStream.write(bytes, 
0, read);
            }

            arrayByte 
= byteArrayOutputStream.toByteArray();
        }
 catch (IOException e) ...{
            
return null;
        }
 finally ...{
            
try ...{
                
if (byteArrayOutputStream != null...{
                    byteArrayOutputStream.close();
                    byteArrayOutputStream 
= null;
                }

                
if (is != null...{
                    is.close();
                    is 
= null;
                }


            }
 catch (IOException e) ...{
            }

        }

        
return arrayByte;
    }


    
/** *//**
     * 获得指定JarInputStream的byte[]形式
     * 
@param jar
     * 
@return
     * 
@throws IOException
     
*/

     
final static private byte[] getResourceData(JarInputStream jar)
            
throws IOException ...{
        ByteArrayOutputStream data 
= new ByteArrayOutputStream();
        
byte[] buffer = new byte[8192];
        
int size;
        
while (jar.available() > 0...{
            size 
= jar.read(buffer);
            
if (size > 0...{
                data.write(buffer, 
0, size);
            }

        }

        
return data.toByteArray();
    }


     
/** *//**
      * 重载的getResource,检查是否重复包含
      
*/

    
public URL getResource(String name) ...{
        
if (resources.containsKey("/" + name)) ...{
            
try ...{
                
return new URL("file:///" + name);
            }
 catch (MalformedURLException e) ...{
                e.printStackTrace();
            }

        }

        
return super.getResource(name);
    }


    
/** *//**
     * 执行指定class类
     * 
@param clz
     * 
@param methodName
     * 
@param args
     
*/

    
public static void callVoidMethod(Class clz, String methodName,
            String[] args) 
...{
        Class[] arg 
= new Class[1];
        arg[
0= args.getClass();
        
try ...{
            Method method 
= clz.getMethod(methodName, arg);
            Object[] inArg 
= new Object[1];
            inArg[
0= args;
            method.invoke(clz, inArg);
        }
 catch (Exception e) ...{
            System.err.println(e.getMessage());
        }

    }

    
     
/** *//**
      * 重载的getResourceAsStream,检查是否重复包含
      
*/

    
public InputStream getResourceAsStream(String name) ...{
        
if (name.charAt(0== '/'...{
            name 
= name.substring(1);
        }

        
if (resources.containsKey("/" + name)) ...{
            
return new ByteArrayInputStream((byte[]) resources.get("/" + name));
        }

        
return super.getResourceAsStream(name);
    }


}


运行示例:

package org.loon.framework.jar;


/** *//**
 * <p>
 * Title: LoonFramework
 * </p>
 * <p>
 * Description:从外部启动jar包
 * </p>
 * <p>
 * Copyright: Copyright (c) 2007
 * </p>
 * <p>
 * Company: LoonFramework
 * </p>
 * 
 * 
@author chenpeng
 * @email:ceponline@yahoo.com.cn
 * 
@version 0.1
 
*/

public class JarTest ...{

    
public static void main(String[] args) ...{
        
//将jar包转为byte[]
        byte[] resource = JarLoader.getDataSource("D:/fps_test.jar");
        
try ...{
            
//通过byte[]获得主函数所在类
            Class clz = JarLoader.load(resource);
            
//调用main函数
            JarLoader.callVoidMethod(clz, "main"new String[] ...{""});
        }
 catch (Exception e) ...{
            e.getStackTrace();
        }


    }


}


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

但是有个缺点,在没有优化的前提下,这种直接加载外部包的速度在jvm会有很大损耗。

我们可以看到,fps值降低到正常值的50%左右(此fps实例见我CSDN以前的文章),所以并不适合直接运用在需要复杂运算的jar中类调用上(当然,有兴趣的话,可以在代码中优化,我自己在项目中写的另一个例子速度明显比这个快)。但是对于运算量小的外部jar调用,还是很方便的。
posted on 2007-11-12 15:38 cping 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/cping1982/archive/2007/11/12/2258094.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PDU (Protocol Data Unit) - 协议数据单元

协议数据单元PDU&#xff08;Protocol Data Unit&#xff09;是指对等层次之间传递的数据单位。 物理层的PDU是数据位&#xff08;bit&#xff09;数据链路层的PDU是数据帧&#xff08;frame&#xff09;网络层的PDU是数据包&#xff08;packet&#xff09;传输层的PDU是数据段…

Git回滚操作的总结

git结构和各操作之间的关系 1&#xff0c;撤销add操作&#xff1a; git reset 2&#xff0c;撤销commit操作&#xff1a; git reset –soft 保留源码&#xff0c;只回退commit信息到某个版本&#xff0c;不涉及index的回退&#xff0c;如果还需要提交&#xff0c;直接commit即…

[Python学习] 模块三.基本字符串

于Python最重要的数据类型包含字符串、名单、元组和字典.本文重点介绍Python基础知识. 一.字符串基础 字符串指一有序的字符序列集合,用单引號、双引號、三重(单双均可)引號引起来.如: s1www.csdn.net s2"www.csdn.net" s3aaabbb 当中字符串又包…

AjaxControlToolkit控件效果演示

http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/Default.aspx div圆角 tags 日期控件等等转载于:https://www.cnblogs.com/freedom831215/archive/2011/12/13/2286051.html

weekendplan

周五晚 交流 能多早睡觉就多早睡觉 周六 给寮母交外出单 打工 外泊 周日 下午返回 整理房间 见高桥 复习 能多早睡觉就多早睡觉 转载于:https://www.cnblogs.com/loverain/archive/2007/11/16/961473.html

Blender建模与游戏换装(转载文)

本文转载自https://my.oschina.net/huliqing/blog/880113?hmsrtoutiao.io 如果本文涉及侵权行为&#xff0c;请原作者联系博主邮箱&#xff0c;我将及时进行删除处理 博主邮箱&#xff1a;yibiandaoaliyun.com 前言 本文将详细讲解3D游戏中换装的原理及换装中的一些重点问题&a…

是否非要用interface关键字来实现接口?

想法我还不能系统的表达, 先发个测试, 大家看看有没有毛病.委托测试:publicdelegateT Func1<T, T1>(T1 t);publicclassFuncTest { publicreadonlyFunc1<long, long>Test; publicFuncTest() { Test Fib; } privatelong…

AS3 调用外部SWF中元件库中的元件 【转】

参考文章&#xff1a; http://www.blueidea.com/tech/multimedia/2008/5842_2.asp 本文来自CSDN博客&#xff0c;转载请标明出处&#xff1a;http://blog.csdn.net/djy1135/archive/2009/11/13/4807925.aspx 一、目的 bb.swf的元件库中有一个元件&#xff0c;在aa.swf中调用这个…

好文章,被架构师秒杀之后

.jdk1.5新增的功能------》2.字符流和字节流的区别&#xff0c;使用场景&#xff0c;相关类 >>>3.线程安全的概念&#xff0c;实现线程安全的几种方法 >>>4.抽象类和接口的区别&#xff0c;使用场景 >>>5.hash算法的实现原理&#xff0c;hash…

出路在哪里?出路在于思路!智者无敌

有人工作&#xff0c;有人继续上学&#xff0c;大家千万不要错过这篇文章&#xff0c;能看到这篇文章也是一种幸运&#xff0c;真的受益匪浅&#xff0c;对我有很大启迪&#xff0c;这篇文章将会改变我的一生&#xff0c;真的太好了&#xff0c;希望与有缘人分享&#xff0c;也…

电缆电压降计算

电缆电压降计算 UI*Z*L I电缆通过的电流 Z电缆阻抗 L电缆长度 阻抗Z可以通过电缆手册中给出的公式计算转载于:https://www.cnblogs.com/tihua/archive/2007/11/23/969627.html

C# 动态添加SEO 信息,不和静态页面重复和叠加

动态添加SEO 信息&#xff0c;不和静态页面重复和叠加&#xff0c;就一个方法&#xff0c;用到了做个记录&#xff0c;以后直接用就OK了&#xff0c;需要的同学也可以直接拿去用。 1 /// <summary> 2 /// 动态设置 SEO 信息 3 /// </summary> 4 /// <pa…

SVN“验证位置时发生错误”的解决办法

验证位置时发生错误:“org.tigris.subversion.javahl.ClientException...... 验证位置时发生错误:“org.tigris.subversion.javahl.ClientException: RA layer request failed svn: Server sent unexpected return value (403 Forbidden) in response to OPTIONS request for h…

Day_03-函数和模块的使用

使用函数求阶乘 使用while循环的代码&#xff1a; m float(input(m ))n float(input(n ))mn m - nfm 1while m ! 1:fm * mm - 1fn 1while n ! 1:fn * nn - 1fmn 1while mn ! 1:fmn * mnmn - 1print(fm // fn // fmn)定义函数块&#xff1a; def C_N_M(parm):fmn 1for …

Visual Studio Team System 2008 Team Suite (90-day Trial)(转)

Visual Studio Team System 2008 Team Suite (90-day Trial) 相关介绍&#xff1a; http://www.microsoft.com/downloads/details.aspx?familyidD95598D7-AA6E-4F24-82E3-81570C5384CB&displaylangen 直接下载地址&#xff1a; http://download.microsoft.com/download/d/…

xml02 XML编程(CRUD)增删查改

XML解析技术概述 Demo2.java import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; public class Demo2 { public static void main(String args[])throws Exception { //1.创建工程 DocumentBuilderFac…

猜数字

写一个猜数字脚本&#xff0c;当用户输入的数字和预设数字&#xff08;随机生成一个小于100的数字&#xff09;一样时&#xff0c;直接退出&#xff0c;否则让用户一直输入&#xff0c;并且提示用户的数字比预设数字大或者小。#!/bin/bashmecho $RANDOMn1$[$m%100]while :do …

3DMax插件和它的3DXI接口

3DXI是3DMax提供给游戏开发者的一套数据读取接口&#xff0c;之前它被称作为IGame。最近一直在搞Ogre的插件相关的文档都很少我相信搞这个的人很多&#xff0c;但是有时间整理拿出来共享的资料实在是太少Ogre自带的maxExplorer只是xml格式&#xff0c;二进制数据的导出竟然未完…

ASP.NET Web Game 架构设计1--服务器基本结构

ASP.NET Web Game 架构设计1--服务器基本结构 1. 基本结构图 2. 系统组成与角色 整个系统大体上分为三个部分&#xff1a;1.网页客户端。2.IIS Web服务器。3.数据库及逻辑服务器。其中Web服务器不处理任何逻辑&#xff0c;它的作用只有两点&#xff1a;1.承载用户。…

人人网 Windows Phone 7 应用开发起步

目前&#xff0c;人人网在国内高校学生中的普及率非常高。前段时间&#xff0c;大概是11月下旬的样子&#xff0c;人人网发布了Windows Phone 7客户端的公测版。我想&#xff0c;Windows Phone 7本地化的优劣&#xff0c;直接关系到其将来在国内的市场份额。而诸如人人等针对学…