当前位置:天才代写 > tutorial > JAVA 教程 > 初探Java类加载机制的机密

初探Java类加载机制的机密

2017-11-11 08:00 星期六 所属: JAVA 教程 浏览:349

副标题#e#

一、在jdk1.2今后,类加载是通过委托来完成的,这意味着假如 ClassLoader 不能找到类,它会请求父代 ClassLoader 来执行此项任务,所有 ClassLoaders 的根是系统 ClassLoader,它会以缺省方法装入类 — 即,从当地文件系统。本日我们就来探讨一下在jvm中这些机制是奈何运行的。让我们假设有一个class字节码文件(好比Hello.class文件),那么在应用措施中,他是如何被加载进来,并形成一个类工具的呢?我们这篇文章的目标就是为了表明这个问题。

在java.lang包里有个ClassLoader类,ClassLoader 的根基方针是对类的请求提供处事。当 JVM 需要利用类时,它按照名称向ClassLoader 请求这个类,然后ClassLoader 试图返回一个暗示这个类的Class工具。通过包围对应于这个进程差异阶段的要领,可以建设定制的ClassLoader。个中有个loadClass(String name, boolean resolve)要领,该要领为ClassLoader的进口点,在jdk1.2今后,loadClass要领将缺省挪用findClass要领,具体内容可以参考API文档,我们编写的ClassLoader主要就是为了包围以上两个要领。回到我们适才的问题,奈何读进字节码文件,并把它组成一个类工具呢?在ClassLoader里有个要领,Class defineClass(String name, byte[] b, int off, int len),谜底就在这里了,我们按照把class字节码文件(如Hello.class)读进一个字节数组里,byte[] b,并把它转化为Class工具,而这些数据可以来历于文件,网络等,神奇吧:)

defineClass打点 JVM 的很多巨大、神秘和倚赖于实现的方面 — 它把字节码阐明成运行时数据布局、校验有效性等等。不必担忧,您无需亲自编写它。事实上,纵然您想要这么做也不能包围它,因为它已被标志成最终的。

其他一些要领:

findSystemClass要领:从当地文件系统装入文件。它在当地文件系统中寻找类文件,假如存在,就利用defineClass 将原始字节转换成 Class工具,以将该文件转换成类。

findClass要领:jdk1.2今后loadClass 的缺省实现挪用这个新要领。findClass 的用途包括您的ClassLoader 的所有非凡代码,而无需要复制其它代码(譬喻,当专门的要领失败时,挪用系统 ClassLoader)。

getSystemClassLoader: 假如包围 findClass 或 loadClass,getSystemClassLoader 使您能以实际 ClassLoader工具来会见系统 ClassLoader(而不是牢靠的从 findSystemClass 挪用它)。

getParent:为了将类请求委托给父代 ClassLoader,这个新要领答允 ClassLoader 获取它的父代 ClassLoader。当利用非凡要领,定制的ClassLoader 不能找到类时,可以利用这种要领。

resolveClass: 可以不完全地(不带理会)装入类,也可以完全地(带理会)装入类。当编写我们本身的loadClass时,可以挪用resolveClass,这取决于loadClass 的resolve 参数的值。

findLoadedClass:充当一个缓存,当请求 loadClass 装入类时,它挪用该要领来查察 ClassLoader 是否已装入这个类,这样可以制止从头装入已存在类所造成的贫苦。应首先挪用该要领。

二、事情流程:

1)挪用findLoadedClass(String) 来查察是否存在已装入的类,假如没有,那么回收那种非凡的神奇方法来获取原始字节。

2)通过父类ClassLoader挪用loadClass要领,假如父类ClassLoader是null,那么按缺省方法装入类,即系统ClassLoader。

3)挪用findClass(String)去查找类并获取类;

4)假如loadClass 的resolve 参数的值为true,那么挪用resolveClass 理会 Class工具.

5)假如还没有类,返回 ClassNotFoundException。

6)不然,将类返回给挪用措施。


#p#副标题#e#

三、一个实现了ClassLoader的例子:

/**
*CompilingClassLoader.java
*Copyright 2005-2-12
*/
import java.io.*;
public class CompilingClassLoader extends ClassLoader{
//读取一个文件的内容
private byte[] getBytes(String filename) throws IOException{
 File file=new File(filename);
 long len=file.length();
 byte[] raw=new byte[(int)len];
 FileInputStream fin=new FileInputStream(file);
 int r=fin.read(raw);
 if(r!=len) throw new IOException("Can't read all,"+r+"!="+len);
 fin.close();
 return raw;
}
private boolean compile(String javaFile) throws IOException{
 System.out.println("CCL:Compiling "+javaFile+"...");
 //挪用系统的javac呼吁
 Process p=Runtime.getRuntime().exec("javac "+javaFile);
 try{
  //其他线程都期待这个线程完成
  p.waitFor();
 }catch(InterruptedException ie){
  System.out.println(ie);
 }
 int ret=p.exitValue();
 return ret==0;
}
public Class loadClass(String name,boolean resovle) throws ClassNotFoundException{
 Class clas=null;
 clas=findLoadedClass(name);
 //这里说明白包的暗示
 String fileStub=name.replace('.','/');
 String javaFilename=fileStub+".java";
 String classFilename=fileStub+".class";
 File javaFile=new File(javaFilename);
 File classFile=new File(classFilename);
 //假如存在class文件就不编译
 if(javaFile.exists()&&(!classFile.exists()||javaFile.lastModified()>classFile.lastModified())){
  try{
   if(!compile(javaFilename)||!classFile.exists()){
    throw new ClassNotFoundException("ClassNotFoundExcetpion:"+javaFilename);
   }
  }catch(IOException ie){
   throw new ClassNotFoundException(ie.toString());
  }
 }
 try{
  byte[] raw=getBytes(classFilename);
  //通过读入数据来结构一个类布局,这是焦点
  clas=defineClass(name,raw,0,raw.length);
 }catch(IOException ie){
  //
 }
 if(clas==null){
  clas=findSystemClass(name);
 }
 System.out.println("findSystemClass:"+clas);
 if(resovle && clas!=null){
  resolveClass(clas);
 }
 if(clas==null){
  throw new ClassNotFoundException(name);
 }
 return clas;
}
}
测试该loader:
/**
*TestRun.java
*Copyright 2005-2-11
*/
import java.lang.reflect.*;
public class TestRun{
 public static void main(String[] args) throws Exception{
  String progClass=args[0];
  String progArgs[]=new String[args.length-1];
  System.arraycopy(args,1,progArgs,0,progArgs.length);
  CompilingClassLoader ccl=new CompilingClassLoader();
  Class clas=ccl.loadClass(progClass);
  //返回一个class的type
  Class[] mainArgType={(new String[0]).getClass()};
  Method main=clas.getMethod("main",mainArgType);
  Object argsArray[]={progArgs};
  main.invoke(null,argsArray);
 }
}

以上的焦点内容已经编写完了,编译后,我们获得两个文件:

CompilingClassLoader.class,TestRun.class

四、编写一个例子,然后运行我们的ClassLoader

#p#分页标题#e#

/**
*Hello.java
*/
public class Hello{
 public static void main(String[] args){
  if(args.length!=1){
   System.err.println("Error,exit!");
   System.exit(1);
  }
  String name=args[0];
  System.out.println("Hello,"+name);
 }
}

好了,运行java TestRun Hello 阿飞

....
....
....
Hello,阿飞

 

    关键字:

天才代写-代写联系方式