Java-----类加载器

原创 2012年03月25日 00:27:16

android培训java培训、期待与您交流!

        类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。基本上所有的类加载器都是 java.lang.ClassLoader类的一个实例。
      Java类加载器主要有两类,一类是开发人员自己编写的,另一类则是系统提供的;系统提供的主要有三种:


        这个图用来表明这三种类加载器的关系是在好不过的了。这个图中的箭头表示方向表示上面的是下面的子类,即BootStrap是最上层的父类加载器了,这个加载器是它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader,它主要用来加载上图右边的文件夹下的jar文件的。ExtClassLoader加载器它用来加载 Java 的扩展库,Java 虚拟机的实现会提供一个扩展库目录,该类加载器在此目录里面查找并加载 Java 类。而至于AppClassLoader加载器它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的,可以通过 ClassLoader.getSystemClassLoader()来获取它。
 这三种类加载器,在加载的时候使用了一种委托的机制。如果类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,依次类推。如下代码:

public class Testx5 {
	public static void main(String[] args) {
		ClassLoader loader = Testx5.class.getClassLoader();
         //返回该类的类加载器。有些实现可能使用 null 来表示引导类加载器。如果该//类由引导类加载器加载,则此方法在这类实现中将返回 null。
		while(loader != null){
			System.out.println(loader.getClass().getName());
			loader = loader.getParent();
             //把该加载器的父类加载器拿到
		}
		System.out.println(loader);
		 }
}
         上面这个代码在加载的时候类加载器会委托给它父类的加载器,父类的加载器并不能在它文件下找到这个jar文件那么就由它本身来加载,则输出的结果是:

sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null

         打印出的结果首先是加载当前文件的加载器,即系统类加载器,然后是它的父类加载器在然后就是引导类加载器了,因为它没有实例所以就返回的是null。
         假如现在我们把这个jar文件加到JRE/lib/ext下,在看看输出的结果是什么:

sun.misc.Launcher$ExtClassLoader
null

        由上面的输入我们就可以看出这个加载的过程虽说是由下层或者本层发出的,但是真正的加载器却是其父类或者本身加载器。这就是委托,总是先把任务往高处推,如果上面的不处理,在由本身来加载。 
       编写自己的类加载器:在视频中老师编写的类加载器是一个加密class加载器。首先实现.class文件可以通过MyClassLoader来进行加密,代码如下:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class MyLoaderClass {
	public static void main(String[] args)throws Exception {
		String srcPath = args[0];
		//传入要进行加密的class绝对路径
		String destDir = args[1];
		//加密后的class要放到哪个目录中
		String destPath = destDir + "\\" +srcPath.substring(srcPath.lastIndexOf('\\')+1);
		//这个是用来得到最后目标路径包括了文件名
		FileInputStream fis = new FileInputStream(srcPath);
		FileOutputStream fos = new FileOutputStream(destPath);
		cypher(fis,fos);
		//调用加密函数
		fis.close();
		fos.close();
	}
	public static void cypher(InputStream is,OutputStream os)throws Exception{
		int b = -1;
		while((b = is.read())!=-1){
			os.write(b ^ 0xff);
			//读取的数据进行与0xff的异或
		}
	}
}
//用来加载的类
import java.util.Date;
public class ClassLoaderAttachment extends Date {
	public String toString(){
		return "hello world";
	}
}

       生成加密后的文件后,然后我们在测试下,看现在在别的类里面我们来调用这个文件,可不可以正常运行,实验证明这个是不能运行,比如我在别的文件中加入

System.out.println(new ClassLoaderAttachment().toString());
运行的结果是:
Exception in thread "main" java.lang.NoClassDefFoundError: ClassLoaderAttachment
	at Testx5.main(Testx5.java:17)
Caused by: java.lang.ClassNotFoundException: ClassLoaderAttachment

        就是说在三种类加载器中都没有找到相应字节码来加载,那么这种情况就需要我们自己的加载器来进行解密了。
       在自己编写加载的时候,必须要继承ClassLoader类,并且复写findClass方法,老师讲在复写的时候我们不能复写loadClass方法,因为这个loadClass方法中有委托机制的一个过程运行,所以为了保存下来,所以覆盖findClass方法。代码:

	private String classDir;
	public MyLoaderClass(){}
	public MyLoaderClass(String classDir){
		this.classDir = classDir;
	}
@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		String className = classDir + "\\" + name + ".class";
		//得到传进来class文件的绝对路径
		try {
			FileInputStream fis = new FileInputStream(className);
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			cypher(fis,baos);
			fis.close();//解密
			byte[] bytes = baos.toByteArray();
			return defineClass(null, bytes, 0,bytes.length);
			//解密后的数据通过这个方法来变为一个字节码
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
然后在进行测试,在另外一个文件中写如下代码:
Class<?> clazz = new MyLoaderClass("itcastlib").loadClass("ClassLoaderAttachment");
Date d = (Date)clazz.newInstance();
System.out.println(d);
最后可以正常的运行出结果,这个说明自己的类加载器已经把这个加密的文件解密了。则就是它进行了加载。


android培训java培训、期待与您交流!



类加载器深入理解

Java类加载器深入理解,包括类加载器的命名空间、类加载器的双亲委派模型的实现原理、Tomcat类加载器体系结构...
  • sunxianghuang
  • sunxianghuang
  • 2016年08月11日 23:21
  • 3473

Java类加载器深入探索

class文件全名称为Java class文件,主要在平台无关性和网络移动性方面使Java更适合网络。它在平台无关性方面的任务是:为Java程序提供独立于底层主机平台的二进制形式的服务。class文件...
  • Evankaka
  • Evankaka
  • 2015年09月21日 08:59
  • 3748

深入类加载器----类加载器的分类和等级

深入类加载器(三)----类加载器的分类和等级                      深入类加载器层次结构(三种类加载器)代理加载模式,双亲委托机制    我们首先要知道在jav...
  • li12412414
  • li12412414
  • 2016年08月13日 00:37
  • 1170

Tomcat类加载器(附JVM类加载器简介)

Tomcat类加载器(附JVM类加载器简介)          学习tomcat类加载器,首先得先看下JVM提供了几种类加载器,毕竟tomcat类加载器是依赖于JVM类加载器的。         ...
  • lantian0802
  • lantian0802
  • 2013年04月13日 17:56
  • 1953

类加载器获取资源路径

一、同一工程中: String path = Thread.currentThread().getContextClassLoader().getResource(".").getPath(...
  • Sco_Pis
  • Sco_Pis
  • 2016年06月22日 23:58
  • 1673

JVM类加载器原理与自定义类加载器

一、类加载器原理 JVM将class文件字节码文件加载到内存中, 并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class 对象,作为方法区类数据的...
  • scgaliguodong123_
  • scgaliguodong123_
  • 2015年07月17日 16:35
  • 2032

Tomcat内核之Tomcat的类加载器

跟其他主流的Java Web服务器一样,Tomcat也拥有不同的自定义类加载器,达到对各种资源库的控制。一般来说,Java Web服务器需要解决以下四个问题: ①   同一个Web服务器里,各个Web...
  • wangyangzhizhou
  • wangyangzhizhou
  • 2014年12月14日 20:25
  • 3815

类加载器内存泄露与tomcat自定义加载器

类加载器如何发生内存泄露,以及Tomcat与类加载器有关的源代码,分析了Tomcat的启动流程...
  • u010723709
  • u010723709
  • 2015年12月14日 10:59
  • 2126

类加载器classLoader加载配置文件多种方法,框架原理--反射

public class FrameReflect { @SuppressWarnings("unchecked") public static void main(String[] args)...
  • curiouslearnerdhh
  • curiouslearnerdhh
  • 2014年05月22日 17:49
  • 779

扩展类加载器-------改变JAVA的父优先类加载顺序

java的类加载机制默认情况下是采用委托模型:当加载某个类时JVM会首先尝试用当前类加载器的父类加载器加载该类,若父类加载器加载不到再由当前类加载器来加载,因此这种模型又叫做“父优先”模型。    但...
  • zhangxinrun
  • zhangxinrun
  • 2011年01月24日 16:09
  • 4218
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java-----类加载器
举报原因:
原因补充:

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