自定义ClassLoader 简单例子

转载 2009年12月10日 16:15:00

转载自 http://www.javaresearch.org/article/1007.htm

 

很多时候人们会使用一些自定义的ClassLoader ,而不是使用系统的Class Loader。大多数时候人们这样做的原因是,他们在编译时无法预知运行时会需要那些Class。特别是在那些appserver中,比如tomcat,Avalon-phonix,Jboss中。或是程序提供一些plug-in的功能,用户可以在程序编译好之后再添加自己的功能,比如ant, jxta-shell等。定制一个ClassLoader很简单,一般只需要理解很少的几个方法就可以完成。一个最简单的自定义的ClassLoader从ClassLoader类继承而来。这里我们要做一个可以在运行时指定路径,加载这个路径下的class的ClassLoader。通常我们使用ClassLoader.loadClass(String):Class方法,通过给出一个类名,就会得到一个相应的Class实例。因此只要小小的改动这个方法,就可以实现我们的愿望了。

 

源码: protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {

// First, check if the class has already been loaded

Class c = findLoadedClass(name);

 if (c == null) {

try { if (parent != null) {

 c = parent.loadClass(name, false);

 }else{ c = findBootstrapClass0(name);

 }

}catch(ClassNotFoundException e){

// If still not found, then call findClass in order

 // to find the class. c = findClass(name);

 }

 } if (resolve) { resolveClass(c);

}

 return c;

}

 

Source from ClassLoader.java First,check JavaAPI doc:上面指出了缺省的loadClass方法所做的几个步骤。 1. 调用findLoadedClass(String):Class 检查一下这个class是否已经被加载过了,由于JVM 规范规定ClassLoader可以cache它所加载的Class,因此如果一个class已经被加载过的话,直接从cache中获取即可。 2. 调用它的parent 的loadClass()方法,如果parent为空,这使用JVM内部的class loader(即著名的bootstrap classloader)。 3. 如果上面两步都没有找到,调用findClass(String)方法来查找并加载这个class。后面还有一句话,在Java 1.2版本以后,鼓励用户通过继承findClass(String)方法实现自己的class loader而不是继承loadClass(String)方法。既然如此,那么我们就先这么做:)

 

public class AnotherClassLoader extends ClassLoader {

private String baseDir;

private static final Logger LOG = Logger.getLogger(AnotherClassLoader.class);

public AnotherClassLoader (ClassLoader parent, String baseDir) {

super(parent); this.baseDir = baseDir;

}

protected Class findClass(String name) throws ClassNotFoundException {

 LOG.debug("findClass " + name);

 byte[] bytes = loadClassBytes(name);

Class theClass = defineClass(name, bytes, 0, bytes.length);//A

 if (theClass == null) throw new ClassFormatError();

return theClass;

}

 private byte[] loadClassBytes(String className) throws ClassNotFoundException {

try {

String classFile = getClassFile(className);

FileInputStream fis = new FileInputStream(classFile);

FileChannel fileC = fis.getChannel();

 ByteArrayOutputStream baos = new ByteArrayOutputStream();

 WritableByteChannel outC = Channels.newChannel(baos);

 ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

 while (true) { int i = fileC.read(buffer);

 if (i == 0 || i == -1) {

 break;

 }

buffer.flip();

outC.write(buffer);

buffer.clear();

 }

fis.close();

 return baos.toByteArray();

} catch (IOException fnfe) {

 throw new ClassNotFoundException(className);

 }

}

private String getClassFile(String name) {

StringBuffer sb = new StringBuffer(baseDir);

 name = name.replace('.', File.separatorChar) + ".class";

sb.append(File.separator + name); return sb.toString();

 }

}

 

[i]Ps:这里使用了一些JDK1.4的nio的代码:)[/i] 很简单的代码,关键的地方就在A处,我们使用了defineClass方法,目的在于把从class文件中得到的二进制数组转换为相应的Class实例。defineClass是一个native的方法,它替我们识别class文件格式,分析读取相应的数据结构,并生成一个class实例。 还没完呢,我们只是找到了发布在某个目录下的class,还有资源呢。我们有时会用Class.getResource():URL来获取相应的资源文件。如果仅仅使用上面的ClassLoader是找不到这个资源的,相应的返回值为null。 同样我们看一下原来的ClassLoader内部的结构。

 

public java.net.URL getResource(String name) {

 name = resolveName(name); ClassLoader cl = getClassLoader0();//这里

if (cl==null) {

// A system class. return ClassLoader.getSystemResource(name);

 }

return cl.getResource(name);

}

 

原来是使用加载这个class的那个classLoader获取得资源。

 

public URL getResource(String name) {

URL url;

 if (parent != null) {

url = parent.getResource(name);

} else { url = getBootstrapResource(name);

} if (url == null) {

url = findResource(name);//这里

}

return url;

}

 

这样看来只要继承findResource(String)方法就可以了。修改以下我们的代码:

 

//新增的一个findResource方法

protected URL findResource(String name) {

 LOG.debug("findResource " + name);

try { URL url = super.findResource(name);

 if (url != null) return url;

 url = new URL("file:///" + converName(name));

//简化处理,所有资源从文件系统中获取 return url;

} catch (MalformedURLException mue) {

LOG.error("findResource", mue); return null;

 }

}

private String converName(String name) {

StringBuffer sb = new StringBuffer(baseDir);

name = name.replace('.', File.separatorChar);

 sb.append(File.separator + name);

return sb.toString();

 }

 

好了,到这里一个简单的自定义的ClassLoader就做好了,你可以添加其他的调料(比如安全检查,修改class文件等),以满足你自己的口味:)

一个自定义类加载器ClassLoader示例

我们的自定义类加载器
  • chenjiazhan
  • chenjiazhan
  • 2014年07月12日 01:34
  • 6812

自定义ClassLoader,让spring加载外部的配置文件和类

今天同事遇到一个需求: 在外部以jar包的形式存放若干个插件,其中包含插件的类,以及spring配置文件;jar包不在classpath里 要实现这个需求,需要用到自定义的ClassLoader,...
  • kyfxbl
  • kyfxbl
  • 2013年09月24日 11:14
  • 3843

Tomcat自定义classLoader加密解密

Tomcat自定义classLoader加密解密
  • DianaCody
  • DianaCody
  • 2014年09月06日 22:57
  • 2902

Android:图解classloader加载class的流程及自定义ClassLoader

java应用环境中不同的class分别由不同的ClassLoader负责加载。 一个jvm中默认的classloader有Bootstrap ClassLoader、Extension ClassLo...
  • ZBJDSBJ
  • ZBJDSBJ
  • 2014年11月20日 14:24
  • 1580

Java 自定义 ClassLoader 实现隔离运行不同版本jar包的方式

1. 应用场景有时候我们需要在一个 Project 中运行多个不同版本的 jar 包,以应对不同集群的版本或其它的问题。如果这个时候选择在同一个项目中实现这样的功能,那么通常只能选择更低版本的 jar...
  • t894690230
  • t894690230
  • 2017年06月14日 21:16
  • 2214

Java Class的热替换 自定义ClassLoader加载.class(java热部署实现 )

本文是java热替换的实验,参考了 Java 类的热替换 —— 概念、设计与实现http://www.ibm.com/developerworks/cn/java/j-lo-hotswapcls...
  • wangxin1982314
  • wangxin1982314
  • 2017年03月23日 14:27
  • 1012

实现自定义类加载器-ClassLoader

JAVA启动后,是经过JVM各级ClassLoader来加载各个类到内存。为了更加了解加载过程,我通过分析和写了一个简单的ClassLoader来粗浅的分析它的原理。 JVM的ClassLoader...
  • zmx729618
  • zmx729618
  • 2015年08月07日 17:16
  • 897

详解ClassLoader加载类的流程及自定义ClassLoader

Java应用环境中不同的class分别由不同的ClassLoader负责加载。 一个jvm中默认的classloader有Bootstrap ClassLoader、Extension ClassL...
  • canlets
  • canlets
  • 2014年05月28日 22:04
  • 2052

深入分析ClassLoader

why?ClassLoader,即java类加载器,主要作用是将class加载到JVM内,同时它还要考虑class由谁来加载。在说java的类加载机制之前,还是像前面的博客一样,先说说为什么要知道ja...
  • tonytfjing
  • tonytfjing
  • 2015年08月02日 22:52
  • 7664

使用自己的ClassLoader实现热替换

首先实现一个自己的ClassLoader
  • is_zhoufeng
  • is_zhoufeng
  • 2014年05月22日 17:00
  • 9331
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:自定义ClassLoader 简单例子
举报原因:
原因补充:

(最多只允许输入30个字)