实现一个简单的自定义类加载器

本文详细介绍了Java虚拟机中的类加载子系统,包括根装载器、扩展类装载器、系统类装载器及其工作原理。并通过自定义类加载器的实现,展示了如何在特定路径下加载类文件。同时,解释了类装载器的委派模式,并提供了关键源代码分析。

java虚拟机中,有一个类加载子系统,它包括了四种类加载器

1、根装载器(启动类装载器)2、扩展类装载器3、系统类装载器4、用户自定义类加载器

根加载器负责加载API里面的类,例如java.lang.object

扩展类装载器复制加载jre中ext包中的类,如C:\Program Files\Java\jdk1.6.0_21\jre\lib\ext

系统类装载器加载classpath中的类,记得我们配置JDK环境变量的时候如何配置classpath的吗?.;C:\Program Files\Java\jdk1.5.0_06\lib\tools.jar; C:\Program Files\Java\jdk1.5.0_06\lib\rt.jar,这些就是classpath里面的类,你程序中的类,也是由它加载的,因为你程序属于当前路径,classpath中有个“.”

补充个知识点(摘至百度):

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

rt.jar ,dt.jar ,tool.jar都是 做什么用的 ,分别什么时候需要设置到classpath里?
---------------------------------------------------------------

rt.jar是JAVA基础类库,dt.jar是关于运行环境的类库,tools.jar是工具类库

设置在classpath里是为了让你 import *
---------------------------------------------------------------

web系统都用到tool.jar

你用winrar看看里面是什么内容啦
---------------------------------------------------------------

1.
rt.jar 默认就在 根classloader的加载路径里面 放在claspath是多此一举
不信你可以去掉classpath里面的rt.jar

然后用 java -verbose XXXX 的方式运行一个简单的类 就知道 JVM的系统根Loader的路径里面

不光rt.jar jre\lib下面的大部分jar 都在这个路径里 

2.

tools.jar 是系统用来编译一个类的时候用到的 也就是javac的时候用到

javac XXX.java

实际上就是运行 

java -Calsspath=%JAVA_HOME%\lib\tools.jar  xx.xxx.Main  XXX.java 

javac就是对上面命令的封装 所以tools.jar 也不用加到classpath里面

3.
dt.jar是关于运行环境的类库,主要是swing的包   你要用到swing时最好加上

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

类装载器是如何装载类的呢?

类装载器采用了父亲委派模式来进行加载,父亲委派模式是这样的,要加载一个类的时候,首先叫负责加载该类的类装载器的父装载器去尝试加载,如果加载不了,再往上抛,一直抛到根加载器,如果根加载器还加载不了,那么就让负责加载该类的类装载器来加载。

根装载器没有父装载器,它是C实现的,所以在程序中获取不到它,扩展类装载器的父装载器是根装载器,系统类装载器的父装载器是扩展类装载器,而用户自定义的类装载器,默认情况下是系统类装载器,当然,在自定义类装载器的时候,是可以指定父装载器的。

讲完了加载的顺序,那么我们就来尝试着写一个类装载器,让它装载固定某个地方的类


首先写一个自己的类加载器,MyClassLoader.java,继承ClassLoader类,然后重写findClass方法:

package com.wyp12.myClassLoader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
 * 自己写一个类加载器 ,去加载"d:\myclass\com\wyp12\*.class"
 * 
 * @author prince
 * 
 */
public class MyClassLoader extends ClassLoader {
	private String name;
	public MyClassLoader(String name) {
		super(); // 通过这个构造方法生成的类加载器,它的父加载器是系统类加载器
		this.name = name;
	}
	public MyClassLoader(String name, ClassLoader loader) {
		super(loader); // 通过这个这个构造方法生成的类加载器,该加载器的父加载器是loader,如果为空,则父加载器为根加载器
		// 子类继承父类,如果不显式写出调用父类的哪个构造方法,那么就默认调用父类的无参构造函数
		this.name = name;
	}
	public String toString()
	{
		return this.name;
	}
	// 要重写findclass这个方法,loadclass会调用它
	 @Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		// TODO Auto-generated method stub
		 byte[] data = null;
		 FileInputStream fis = null;
		try {
			fis = new FileInputStream("d:\\myclass\\com\\wyp12\\myClassLoader\\"+name+".class");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		 ByteArrayOutputStream abos = new ByteArrayOutputStream();
		 int ch = 0;
		 try {
			while (-1!=(ch=fis.read()))
			 {
				  abos.write(ch);        //把字节一个一个写到输出流中
			 }
		} catch (IOException e) {
			e.printStackTrace();
		}
		 data = abos.toByteArray();   //把输出流中的字节弄成一个字节数组
		return this.defineClass("com.wyp12.myClassLoader."+name,data, 0, data.length,null);
           }
}
这个类加载器我让它默认加载
d:\myclass\com\wyp12\myClassLoader
路径下的class文件,具体文件名到时候我们构造实例的时候再给定,下面是测试类:

import com.wyp12.myClassLoader.MyClassLoader;
public class TestLoader {
	public static void main(String[] args) throws Exception {
		MyClassLoader l1 = new MyClassLoader("loader1");
	 	Class dogC = l1.loadClass("Dog");
	 	dogC.newInstance();
		/*MyClassLoader l2 = new MyClassLoader("loader2",l1);  //把L1作为它的父加载器
		Class doccc = l2.loadClass("Dog");
		doccc.newInstance(); */
	}
}

下面是要加载的类的源代码,很简答,就是让它打印出是谁加载了他

package com.wyp12.myClassLoader;

public class Dog {
    public Dog()
    {
        System.out.println(this.getClass().getClassLoader());
    }
}


运行结果:

loader1


下面贴上ClassLoader的主要源代码:

它的几个构造函数

protected ClassLoader() {
        this(checkCreateClassLoader(), getSystemClassLoader());
    }
protected ClassLoader(ClassLoader parent) {
        this(checkCreateClassLoader(), parent);
    }
protected ClassLoader() {
        this(checkCreateClassLoader(), getSystemClassLoader());
    }

通过几个函数,把字节码数组转换成一个CLASS实例

  protected final Class<?> defineClass(String name, byte[] b, int off, int len,
                     ProtectionDomain protectionDomain)
    throws ClassFormatError
    {
         return defineClassCond(name, b, off, len, protectionDomain, true);
    }

    // Private method w/ an extra argument for skipping class verification
    private final Class<?> defineClassCond(String name,
                                           byte[] b, int off, int len,
                                           ProtectionDomain protectionDomain,
                                           boolean verify)
        throws ClassFormatError
    {
    protectionDomain = preDefineClass(name, protectionDomain);

    Class c = null;
        String source = defineClassSourceLocation(protectionDomain);

    try {
        c = defineClass1(name, b, off, len, protectionDomain, source,
                             verify);
    } catch (ClassFormatError cfe) {
        c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,
                                       source, verify);
    }

    postDefineClass(c, protectionDomain);
    return c;
    }

下面这个是loadClass()

public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
    }
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 = findBootstrapClassOrNull(name);
		}
	    } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }
            if (c == null) {
	        // If still not found, then invoke findClass in order
	        // to find the class.
	        c = findClass(name);
	    }
	}

下面是我们要重写的方法:

protected Class<?> findClass(String name) throws ClassNotFoundException {
	throw new ClassNotFoundException(name);
    }

基本就这样了,其实还很多细节,由于自己的文笔也不是很好,就不写出来了,只是做个mark,以后便于复习























评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值