您的位置:首页 > 编程语言 > Java开发

运用URLClassLoader加载外部jar包的java类,生成Class文件

2012-11-23 11:18 633 查看
先来一段网上copy的话术:

//****************************

很多时候我们写的java程序是分模块的,有很好的扩展机制,即我们可以为我们自己的java类添加插件,来运行将来某天我们可能开发出来的类,以下称这些类为插件类。

下边是一种简单的实现方法:

ClassA作为程序的主入口,其中包含了程序的执行入口(main)函数。然后在main函数中通过外部的配置文件,然后通过外部的配置文件,我们可以获得插件类的信息(位于哪个jar包,jar包的具体路径),然后获得jar包中某一个类的实例,来完成相应的工作。这个jar包很可能是外部的jar包,是我们自己写好的,那么我们放到哪里,他才能自己找到呢?我尝试过很多次,除非将其具体目录,放到class_path中才可以成功执行,否则报的异常只有一个ClassNotFoundException,就是找不到类。不过还有一种方法,就是将该jar包解压到运行jar包所在的目录,这样就可以通过class_path中的.来获得相应的类了。不过这样会显得很不专业,java写出来的东西都是jar包啊,自己感觉的。放到claspath中,不能每次写出新的jar包都配置一遍吧!

如此出现了如下的解决办法:

想了解解决办法的含义,首先要了解java的类加载机制。众所周知,程序若想执行,必须加载到内存当中才能成功执行。java程序并不是可执行文件,由许多独立的类文件来完成。所以java中加载程序是以类为单外来完成的。这也就需要我们来简单了解一下java的classloader加载机制。

java程序开始执行,遇到的第一个classloader是bootstrapclassloader,这个classloader是用c++语言编写,通过他来完成加载java中的核心类。第二个classloader是extensionclassloader,加载的是jre/lib目录中的ext目录中的jar包。然后第三个是systemclassloader,也被称为应用加载器,主要负责完成加载-classpath或者系统中的全局变量ClassPath中的类。System.out.println(System.getProperty(“java.class.path”));可以获得classpath的配置,也就是system
classloader加载的类,第四个classloader可能是用户自定义的加载器,来自定义加载类。通常一个类的加载过程是这样的通过当前的类加载器的父加载器尝试查找,如果没有再找其父加载器尝试加载,直到最终的bootstrapclassloader为止,如果还没有找到,那么就开始从上往下加载类。这样做的目的是防止自定义的类来覆盖系统中的类,如果没有这种机制很容易出现这种笑话,自己写了一个String类,然后newstring的时候是自己写的String类,这样就比较好玩了。

//*********************************************

下面是我最近做项目的实际代码,可以作为参考:

1.自己定义URLClassLoader对象加载外部jar包,针对jar包里面不再出现别的jar包的情况,即只解析.class文件:

privatestaticvoidtest1(){
Stringpath="D:\\test.jar";//外部jar包的路径
Set<Class<?>>classes=newLinkedHashSet<Class<?>>();//所有的Class对象
Map<Class<?>,Annotation[]>classAnnotationMap=newHashMap<Class<?>,Annotation[]>();//每个Class对象上的注释对象
Map<Class<?>,Map<Method,Annotation[]>>classMethodAnnoMap=newHashMap<Class<?>,Map<Method,Annotation[]>>();//每个Class对象中每个方法上的注释对象
try{
JarFilejarFile=newJarFile(newFile(path));
URLurl=newURL("file:"+path);
ClassLoaderloader=newURLClassLoader(newURL[]{url});//自己定义的classLoader类,把外部路径也加到load路径里,使系统去该路经load对象
Enumeration<JarEntry>es=jarFile.entries();
while(es.hasMoreElements()){
JarEntryjarEntry=(JarEntry)es.nextElement();
Stringname=jarEntry.getName();
if(name!=null&&name.endsWith(".class")){//只解析了.class文件,没有解析里面的jar包
//默认去系统已经定义的路径查找对象,针对外部jar包不能用
//Class<?>c=Thread.currentThread().getContextClassLoader().loadClass(name.replace("/",".").substring(0,name.length()-6));
Class<?>c=loader.loadClass(name.replace("/",".").substring(0,name.length()-6));//自己定义的loader路径可以找到
System.out.println(c);
classes.add(c);
Annotation[]classAnnos=c.getDeclaredAnnotations();
classAnnotationMap.put(c,classAnnos);
Method[]classMethods=c.getDeclaredMethods();
Map<Method,Annotation[]>methodAnnoMap=newHashMap<Method,Annotation[]>();
for(inti=0;i<classMethods.length;i++){
Annotation[]a=classMethods[i].getDeclaredAnnotations();
methodAnnoMap.put(classMethods[i],a);
}
classMethodAnnoMap.put(c,methodAnnoMap);
}
}
System.out.println(classes.size());
}catch(IOExceptione){
e.printStackTrace();
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
}

以上的这种情况可以在别的project项目里写test方法,是平时最常用的,如果当.class文件里有依赖别的jar包里的对象的时候,就要把该jar包拷贝到写此测试方法的project并buildPath,不然的话运行的时候会报找不到Class对象的异常。

2.第二种情况是针对加载jar包里面的jar包的Class对象,还有读取某一个properties文件的方法。

privatestaticvoidtest2(){
Stringpath="D:\\test.jar";//此jar包里还有别的jar包
try{
JarFilejarfile=newJarFile(newFile(path));
Enumeration<JarEntry>es=jarfile.entries();
while(es.hasMoreElements()){
JarEntryje=es.nextElement();
Stringname=je.getName();
if(name.endsWith(".jar")){//读取jar包里的jar包
Filef=newFile(name);
JarFilej=newJarFile(f);
Enumeration<JarEntry>e=j.entries();
while(e.hasMoreElements()){
JarEntryjarEntry=(JarEntry)e.nextElement();
System.out.println(jarEntry.getName());
//.........接下去和上面的方法类似
}
}
//System.out.println(je.getName());
if(je.getName().equals("entity_pk.properties")){
InputStreaminputStream=jarfile.getInputStream(je);
Propertiesproperties=newProperties();
properties.load(inputStream);
Iterator<Object>ite=properties.keySet().iterator();
while(ite.hasNext()){
Objectkey=ite.next();
System.out.println(key+":"+properties.get(key));
}
}
}
}catch(IOExceptione){
e.printStackTrace();
}
}

3.第三种情况是在该项目下获取某个包的Class对象,当然了,测试方法是在该项目下写的(这样classLoader就直接可以知道对象了,不需要再自定义URLClassLoader了,用Thread.currentThread().getContextClassLoader().loadClass(.....)就可以直接获得Class对象了,回去ClassPath下找,System.out.print(System.getProperty("java.class.path"))就可以找到classPath路径)。

privatestaticSet<Class<?>>getclass(){
Set<Class<?>>classes=newLinkedHashSet<Class<?>>();
booleanflag=true;//是否循环迭代

StringpackName="com.yk.framework.db";
//StringpackName="org.jdom";
StringpackDir=packName.replace(".","/");
Enumeration<URL>dir;
try{
dir=Thread.currentThread().getContextClassLoader().getResources(packDir);
while(dir.hasMoreElements()){
URLurl=dir.nextElement();
System.out.println("url:***"+url);
Stringprotocol=url.getProtocol();//获得协议号
if("file".equals(protocol)){
System.err.println("file类型的扫描");
StringfilePath=URLDecoder.decode(url.getFile(),"UTF-8");
System.out.println("filePath:"+filePath);
findAndAddClassesInPackageByFile(packName,filePath,flag,classes);
}elseif("jar".equals(protocol)){
System.err.println("jar类型扫描");
JarFilejar;
jar=((JarURLConnection)url.openConnection()).getJarFile();
Enumeration<JarEntry>entries=jar.entries();
while(entries.hasMoreElements()){
JarEntryentry=entries.nextElement();
Stringname=entry.getName();
System.out.println(">>>>:"+name);
//......
}

}

}

}catch(IOExceptione){
e.printStackTrace();
}
System.out.println(classes.size());
returnclasses;

}

下面上第二段代码

privatestaticvoidfindAndAddClassesInPackageByFile(StringpackName,StringfilePath,finalbooleanflag,Set<Class<?>>classes){
Filedir=newFile(filePath);
if(!dir.exists()||!dir.isDirectory()){
System.out.println("此路径下没有文件");
return;
}
File[]dirfiles=dir.listFiles(newFileFilter(){
@Override
publicbooleanaccept(Filepathname){
returnflag&&pathname.isDirectory()||pathname.getName().endsWith(".class");
}
});
for(Filefile:dirfiles){
if(file.isDirectory()){//如果是目录,继续扫描
findAndAddClassesInPackageByFile(packName+"."+file.getName(),file.getAbsolutePath(),flag,classes);
}else{//如果是文件
StringclassName=file.getName().substring(0,file.getName().length()-6);
System.out.println("类名:"+className);
try{
classes.add(Thread.currentThread().getContextClassLoader().loadClass(packName+"."+className));
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
}
}
}

好了,大致就是这样,好好学习,天天向上!哈哈~~

补充:

4.读取jar包中的entity_pk.properties键值对到项目本地entity_pk.properties文件中

	/**
*读取jar包中的entity_pk.properties键值对到项目本地entity_pk.properties文件中
*/
privatestaticvoidtest2(){
Stringpath="D:\\test.jar";
try{
JarFilejarFile=newJarFile(newFile(path));
Enumeration<JarEntry>es=jarFile.entries();
while(es.hasMoreElements()){
JarEntryjarEntry=(JarEntry)es.nextElement();
Stringname=jarEntry.getName();
if(name.equals("entity_pk.properties")){
InputStreaminputStream=newFileInputStream(name);
Propertiesprop=newProperties();
prop.load(inputStream);//先load本地的entity_pk.propertoes文件
InputStreaminputStream2=jarFile.getInputStream(jarEntry);//获得jar包entity_pk.propertoes文件流
Propertiesprop2=newProperties();
prop2.load(inputStream2);
Enumeration<Object>ks=prop2.keys();
OutputStreamout=newFileOutputStream(name);
while(ks.hasMoreElements()){
Stringkey=(String)ks.nextElement();
System.out.println(key+":"+prop2.getProperty(key));
prop.setProperty(key,prop2.getProperty(key));//把jar包entity_pk.properties键值对放入本地
}
prop.store(out,"");
}
}

}catch(IOExceptione){
e.printStackTrace();
}

}


5.读写db_config.xml文件

	/**
*读写db_config.xml文件
*/
privatestaticvoidtest3(){
Stringpath="D:\\test.jar";
try{
JarFilejarFile=newJarFile(newFile(path));
Enumeration<JarEntry>es=jarFile.entries();
while(es.hasMoreElements()){
JarEntryjarEntry=(JarEntry)es.nextElement();
Stringname=jarEntry.getName();
if(name.equals("db_config.xml")){
InputStreaminputStream=jarFile.getInputStream(jarEntry);
SAXBuilderbuilder=newSAXBuilder();
Documentdoc=null;
try{
doc=builder.build(inputStream);
if(doc!=null){
Elemente=doc.getRootElement();
Elementproxool=e.getChild("proxool");
List<Element>children=proxool.getChildren();
for(Elementelement:children){
System.out.println(element.getText());
}
Elements=newElement("test");
s.addContent("test");
proxool.addContent(s);
XMLOutputteroutputter=newXMLOutputter();
outputter.output(doc,newFileOutputStream("config/db_config.xml"));
}
}catch(JDOMExceptione){
e.printStackTrace();
}finally{
if(inputStream!=null){
inputStream.close();
}
}

}

}

}catch(IOExceptione){
e.printStackTrace();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: