论坛首页 Java企业应用论坛

JavaClassLoader的一些热运用(来拍砖吧!)

浏览 4148 次
精华帖 (0) :: 良好帖 (3) :: 新手帖 (1) :: 隐藏帖 (2)
作者 正文
   发表时间:2010-03-11   最后修改:2010-03-11
  由于一个JDBC的基本封装引来众多砖块,其实对本人来说是好事!毕竟能够学到点东西。由于在使用到Class.forName()方法,就进而对Class Loader有了疑惑,因此查阅了一些资料,这里来进行个人学习的总结。不过如果有建议或者拍砖。本人非常感谢!

  下面是我对Class Loader进行一点总结

在Java中,类的实例化流程分为两个部分:类的加载和类的实例化。类的加载分为显式加载和隐式加载。大家都知道使用new关键字创建类实例,那么new其实属于隐式地包含了类的加载过程。那么什么又是显式的加载呢?其实Class.forName就是一个最常用的。不管隐式还是显式都是通过调用ClassLoader类的loadClass方法来完成类的实际加载工作。但是如果直接调用ClassLoader的loadClass方法是一种不常见的显式加载类的技术。但是现在也在一些框架中使用了。

这样看起来好像ClassLoade没什么内涵。但是细心去研究发现其实Java类加载器是有层次的。ClassLoader在加载类时有一定的层次关系和规则。在Java中,有四种类型的加载器,分别是 Bootstrap class loader、Extensions class loader、System class loader以及用户自定义的类加载器。现在来看看上面四种类型的加载器的职责。
引用

1. Bootstrap Class loader:该类加载器层次结构的最高层,直接负责<JAVA_HOME>/lib目录下的的核心API或-Xbootclasspath选项指定的jar包。

2. Extensions Class Loader:该类主要负责默认为<JAVA_HOME>/lib/ext目录或者-Djava.ext.dirs指定目录下的jar包加载。

3. System class loader:主要负责加载路径为java.class.path,默认为环境变量CLASSPATH中设定的值。

4. 用户自定义的类加载:根据用户的需要定制自己的类加载过程,在运行期进行指定类的动态实时加载。

大致就这四种那个类的加载。问题是他们有层次。看看他们在加载过程:
加载类的顺序:
引用

Bootstrap Class loader --> Extensions Class Loader -->System class loader ---->用户自定义的类加载;他们都是在直接的加载路径上进行加载。

对类是否加载过进行判断的过程则是加载类的逆序。

每个类加载器都有直接的名字空间,对于同一个类加载器实例来说,名字相同的类只能存在一个,并且仅仅加载一次。不管该类有没有变化,下次再需要加载时候,它只是从自己的缓存中直接返回已经加载过的类引用。我们自己编写的类默认情况下都是通过System ClassLoader进行加载的。当我们使用new关键字或者class.forName来加载类时,所有加载的类则调用SystemClassLoader进行加载。
通过上面的分析大概知道了一点类的加载机制了吧。以及各自的加载路径。
引用

设想:
  既然知道我们知道类的加载机制和不同加载路径。我们是否会想到一个这样的问题。就是我们常常用SVN类纪录代码的版本。我们能不能利用类的加载机制来尝试加载一个类的不同版本的共存呢?利用不同类的加载机制和类加载机制的路径来加载该类的另外一个不同的版本呢?因此为了充分发挥用户自定义类加载机制,以下将试试利用自己的类加载器,对类的过程进行加载和控制和管理。


实施步骤:
1. 编写自定义的类加载
      分析得出编写自定义的类加载器,必须要去继承ClassLoader。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashSet;

/**
 * Description: 1. 要实现同一个类的不同版本的共存,那么这些不同版本必须有不同的类加载器进行加载
 *              2. 不能采用默认的加载器来进行加载类
 * @author Developer
 */
public class CustomerClassLoader extends ClassLoader {
	private String basedir; //需要该类加载器直接加载的类文件的基目录
	private HashSet dynaclazz; //需要由该类加载器直接加载的类名
	
	public CustomerClassLoader(String basedir,String[] clazz) throws IOException{
		super(null);//防止父类进行加载
		this.basedir = basedir;
		dynaclazz = new HashSet();
		loadClassByMe(clazz);
	}
	
	/**
	 * 
	 * @param clazns
	 * @throws IOException 
	 */
	private void loadClassByMe(String[] clazns) throws IOException{
		for(int i=0;i<clazns.length ; i++){
			loadDirectly(clazns[i]);
			dynaclazz.add(clazns[i]);
		}
	}
  
	
	 /**
	  * 
	  * @param name
	  * @return
	 * @throws IOException 
	  */
	private Class loadDirectly(String name) throws IOException {
       Class cls = null;
       StringBuffer sb = new StringBuffer(basedir);
       String classname = name.replace('.', File.separatorChar)+".class";
       sb.append(File.separator + classname);
       File classF = new File(sb.toString());
       cls = instantiateClass(name,new FileInputStream(classF),classF.length());
       return cls;
	}
	
	/**
	 * 
	 * @param name
	 * @param fileInputStream
	 * @param len
	 * @return
	 * @throws IOException
	 */

	private Class instantiateClass(String name,
			FileInputStream fileInputStream, long len) throws IOException {
		  byte[] raw = new byte[(int)len];
		  fileInputStream.read(raw);
          fileInputStream.close();
		return  defineClass(name,raw,0,raw.length);
	}
	
	protected Class loadClass(String name,boolean resolve)throws ClassNotFoundException{
		Class cls = null;
		cls = findLoadedClass(name);
		 if(!this.dynaclazz.contains(name) && cls == null)
			 cls = getSystemClassLoader().loadClass(name);
		 if(cls == null)
			 throw new ClassNotFoundException(name);
		 if(resolve)
			 resolveClass(cls);
		return cls;
		
	}
}

以上基本代码已经完成,如果有兴趣可以看看,写一个类来试试。看能不能替换。
如果真正能够明白,我想利用该机制能够很好的做好类的热运行。不在停止服务情况下,进行升级。
代码肯定不够好,希望各位好好拍。附件中有一个.pdf资料。想深入了解可以研究下。

参考的一些资料有:
http://en.wikipedia.org/wiki/Java_Classloader
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html
   发表时间:2010-03-12  
热运动??好像没怎么解释这个名称哦。。对这个有点兴趣,能否解析下。
0 请登录后投票
   发表时间:2010-03-12   最后修改:2010-03-12
http://www.iteye.com/topic/612437
这里有些讨论
0 请登录后投票
   发表时间:2010-03-12  
写道
每个类加载器都有直接的名字空间,对于同一个类加载器实例来说,名字相同的类只能存在一个,并且仅仅加载一次。不管该类有没有变化,下次再需要加载时候,它只是从自己的缓存中直接返回已经加载过的类引用。

 

 仅仅加载一次,下次再需要加载时,这样的说法是否有矛盾?

0 请登录后投票
   发表时间:2010-03-12  
pw04_5 写道
写道
每个类加载器都有直接的名字空间,对于同一个类加载器实例来说,名字相同的类只能存在一个,并且仅仅加载一次。不管该类有没有变化,下次再需要加载时候,它只是从自己的缓存中直接返回已经加载过的类引用。

 

 仅仅加载一次,下次再需要加载时,这样的说法是否有矛盾?

这个指的是从缓存读取,就是class文件加载一次。

0 请登录后投票
   发表时间:2010-03-12  
perm区就是放这些的地方
0 请登录后投票
   发表时间:2010-03-13   最后修改:2010-03-13
lz的这种想法很好,我好像看到有这样实现升级的系统【那是一个老外写的系统】。
jiangduxi 写道

以上基本代码已经完成,如果有兴趣可以看看,写一个类来试试。看能不能替换。
如果真正能够明白,我想利用该机制能够很好的做好类的热运行。不在停止服务情况下,进行升级。

0 请登录后投票
   发表时间:2010-03-13  
xiezuoming 写道
lz的这种想法很好,我好像看到有这样实现升级的系统【那是一个老外写的系统】。
jiangduxi 写道

以上基本代码已经完成,如果有兴趣可以看看,写一个类来试试。看能不能替换。
如果真正能够明白,我想利用该机制能够很好的做好类的热运行。不在停止服务情况下,进行升级。


你好能不能将你看见的那个系统发个网址给我看看。我发现现在的OSGI好像类似。但是好像和我想法不一样。我想的是通过这个加载机制进行升级系统。但是苦于没有找到一个类似的案例。
0 请登录后投票
   发表时间:2010-03-13  
我前几天刚在IBM的开发网站上看过
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics