URLClassLoader应用

Java虚拟机中定义了一个类装载器子系统和执行引擎子系统.其中类装载器子系统主要是负责装载类二进制文件到JVM中的,而执行引擎子系统则负责执行其中的指令.二者都是虚拟机的具体实现,执行引擎程序代码中无法控制,相对来说类装载器就比较灵活.JVM规范中定义虚拟机必须实现启动类装载器(bootstarp),但是用户可以定义自己的类装载器.一个程序启动的时候有3个类加载器.

第一个是启动类加载器,它负责加载Java的核心类.它是JVM实现的一部分,不是ClassLoader的子类.是用C代码实现的.第二个类加载器是扩展类加载器,它负责加载JDK的扩展类,也就是目录配置属性.第三个是APP的类加载器,通常用ClassLoader.getSystemClassLoader()可以获得,负责加载CLASSPATH下的类.一般这3个类加载器足以满足我们的应用.虽然假如我们的程序需要加载上述3个加载器不能到达类.那么我们就只能定义自己的类加载器.

  1. public static void main(String[] args) throws Exception  
  2. {  
  3.     try  
  4.     {  
  5.         Class.forName("org.apache.commons.lang.StringUtils");  
  6.     }  
  7.     catch(Exception e)  
  8.     {  
  9.         e.printStackTrace();  
  10.     }  
  11.   
  12.     File file = new File("D:"+File.separator+"commons-lang-2.5.jar");  
  13.     URL url = file.toURI().toURL();  
  14.     URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});  
  15.     Class clazz = urlClassLoader.loadClass("org.apache.commons.lang.StringUtils");  
  16.     Method isEmpty = clazz.getMethod("isEmpty", String.class);  
  17.   
  18.     System.out.println(isEmpty.invoke(null,"This is not empty!"));  
  19.     System.out.println(isEmpty.invoke(null,""));  
  20. }  

假设在D盘放置了一个apache的commons-lang包,想调用其中的方法,但是我们没有把他引入到classpath.所以在上述的3个ClassLoader中根本就找不到该类的存在.如上述代码用Class.forName方法加载类,此时使用的是AppClassLoader,它的上层ClassLoader也没有该类的引用.所以自然会报出java.lang.ClassNotFoundException的异常出来.所以我们必须定义自己的ClassLoader去加载它,这时候URLClassLoader 就派上用场了.它接受一个URL数组为参数,代表的意义是它可以在提供的路径中加载到提供的类.于是上述代码就可以使用loadClass来加载返回一个Class对象.然后用java反射来调用加载的类的方法.上述代码是调用了org.apache.commons.lang.StringUtils的静态方法isEmpty.

在WEB容器的实现中也用了此方法.有兴趣的话可以参考下Tomcat的源码.容器启动的时候Bootstrap在设置完基本的目录之后,第一件事就是先调用initClassLoaders来构造自己的类加载器层次.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章