`

关于Classloader的总结!loadClass的分析和加载细节的分析

阅读更多
package com.test.one;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;


public class AutoClassLoader extends ClassLoader {

    //定义文件所在目录
    private static final String DEAFAULTDIR="C:/Documents and Settings/liuzhe.pt/Workspaces/MyEclipse 8.5/test/bin/";;
    //定义文件绝对路径
    private static String FILEPATH="";
    
    /*
    * 重写ClassLoader类的findClass方法,将一个字节数组转换为 Class 类的实例
    */
    public Class<?> findClass(String name) throws ClassNotFoundException {
    	System.out.println("----------" +
    			"");
    	 //Class c2=findLoadedClass("com.test.one.tow");
//         if(c2==null){
//         	System.out.println(" ...null");
//         
//         }
        byte[] b = null;
        try {
            b = loadClassData(AutoClassLoader.FormatClassName(name));
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("findclass-----over");
        return defineClass("com.test.one.tow", b, 0, b.length);

    }
    private byte[] loadClassData(String filepath) throws Exception {
        int n =0;
        BufferedInputStream br = new BufferedInputStream(
                        new FileInputStream(
                    new File(filepath)));
        ByteArrayOutputStream bos= new ByteArrayOutputStream();
            while((n=br.read())!=-1){
                bos.write(n);
            }
            br.close();
        return bos.toByteArray();
    }
  //  @Override
    public Class loadClass(String name){
    	System.out.println(name);//输出要加载的类!!!
    	 System.out.println(name.indexOf("java."));
    	 if(name.indexOf("java.")<5&&name.indexOf("java.")>-1){return null;}
		 Class c2=findLoadedClass("com.test.one.tow");
		
		 String path=AutoClassLoader.FormatClassName(name);
		 System.out.println("loadclass"+path);
		// 
		byte[] b = null;
		try {
		    b = loadClassData(path);
		} catch (Exception e) {
		    e.printStackTrace();
		}
		System.out.println("loadclass-----over"+path);
		return defineClass("com.test.one.tow", b, 0, b.length);
    }
    /*
    * 格式化文件所对应的路径
    */
    public static String FormatClassName(String name){
        
        FILEPATH= DEAFAULTDIR+name+".class";
        return FILEPATH;
    }
        
    /*
    * main方法测试
    */
    public static void main(String[] args) throws Exception {
        
        AutoClassLoader acl = new AutoClassLoader();
        //stem.out.println("-----2-----");
        Class c = acl.findClass("com/test/one/tow");
       
        //Object obj = c.newInstance();
        //Method m = c.getMethod("getName",new Class[]{String.class ,int.class});
        //m.invoke(obj,"你好",123);
        System.out.println(c.getName());
        System.out.println(c.getClassLoader());
        System.out.println(c.getClassLoader().getParent());
        System.out.println(AutoClassLoader.class.getClassLoader());
    }
}

这个源码是自定义Classloader的一个类
他定义了loadData()loadClass()findClass()
但如果你运行这个代码的话你会发现 一直报错!他是用自定义的ClassLoader加载
com.test.one.tow(一个简单的类)
说找不到 java.lang.object这个类
当然是在你指定的路径下找不到了!@
怎么出来个 java.lang.object
不知道还记得 加载类的话 他会把所有的父类都要加载一遍  直到java.lang.object
这个实现的方法是在Classloader的loadClass中实现的!
(loadClass是由defineClass1(Native Method)调用的!)
(如果你给tow定义一个父类 你就会发现输出中有加载父类的代码)
你运行了findClass  为什么会运行loadClass呢
因为你在defineClass的时候  他会自动去加载父类的class文件 这些都是Native方法
在Classloader中可以看见!其中会调用loadClass去调用
其中还会调用loadClass去加载
看下报的错误
java.io.FileNotFoundException: C:\Documents and Settings\liuzhe.pt\Workspaces\MyEclipse 8.5\test\bin\java.lang.Object.class (系统找不到指定的文件。)
	at java.io.FileInputStream.open(Native Method)
	at java.io.FileInputStream.<init>(Unknown Source)
	at com.test.one.AutoClassLoader.loadClassData(AutoClassLoader.java:40)
	at com.test.one.AutoClassLoader.loadClass(AutoClassLoader.java:61)
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClassCond(Unknown Source)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at com.test.one.AutoClassLoader.findClass(AutoClassLoader.java:34)
	at com.test.one.AutoClassLoader.main(AutoClassLoader.java:84)
Exception in thread "main" java.lang.NullPointerException
	at com.test.one.AutoClassLoader.loadClass(AutoClassLoader.java:66)
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClassCond(Unknown Source)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at com.test.one.AutoClassLoader.findClass(AutoClassLoader.java:34)
	at com.test.one.AutoClassLoader.main(AutoClassLoader.java:84)

可以看出 调用了 AutoClassLoader的方法loadClass,然后再往下看又一个ClassLoader的defineClass1  这是一个本地方法!也就是说 defineClass1调用了loadClass的方法 ,但是由于调用方法的对象AutoClassLoader有自定义方法loadClass
所以根据多态性,所以就调用了子类自己的方法!
然而自己的方法显然找不到自己的方法
但是你可以这样写 loadClass!!
   public Class loadClass(String name){
    	System.out.println(name);
    	 System.out.println(name.indexOf("java."));
    	 if(name.indexOf("java.")<5&&name.indexOf("java.")>-1){try {
		//如果是java.开头的交给父类的方法获得Class实例!这样就OK	
			return super.loadClass(name);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}}
		 Class c2=findLoadedClass("com.test.one.tow");
		
		 String path=AutoClassLoader.FormatClassName(name);
		 System.out.println("loadclass"+path);
		// 
		byte[] b = null;
		try {
		    b = loadClassData(path);
		} catch (Exception e) {
		    e.printStackTrace();
		}
		System.out.println("loadclass-----over"+path);
		return defineClass("com.test.one.tow", b, 0, b.length);
    }

下面是最终执行的defineClass的源码
 protected final Class<?> defineClass(String name, byte[] b, int off, int len,
					 ProtectionDomain protectionDomain)
	throws ClassFormatError
    {
	check();
	protectionDomain = preDefineClass(name, protectionDomain);

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

	try {
	    c = defineClass1(name, b, off, len, protectionDomain, source);//上面报错的地方////
	} catch (ClassFormatError cfe) {
	    c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source);
	}

	postDefineClass(c, protectionDomain);
	return c;
    }

    }

可以看出先要交给父加载器去加载
这时根据多态性,调用loadClass时会使用重写的方法
所以这时加载父类,name成为了java。lang。object
在目录下当然找不到了!!
所以自定义Classloader的时候 不要重写loadClass

大体流程是这样的e

用户自定义findClass
|
|
defineClass
|
|
defineClass1(Native method)
|
|
加载父类

|------>调用loadClass加载父类(多态性)
|
----loadClass(用户自定义)(所以如果自定义这个类要把系统类交给                  --------------Classloader处理---交给上层的classLoader处理)
|
|
找不到object类
|
|
报错


重写findClass就可以!以免因为加载父类造成异常
另外推荐关于这个的文章
http://tech.sina.com.cn/s/2009-09-02/00351051784.shtml
http://www.cnblogs.com/leo-cnblogs/
或者去我的DBback下载
http://www.dbank.com/download.action?t=40&k=NDc4NjI1MzU=&pcode=LCwxMTI5OTgxLDExMjk5ODE=&rnd=4
分享到:
评论

相关推荐

    classloader 总结

    例如,研究ClassLoader的loadClass()方法以及其子类的实现,可以更清晰地了解类加载过程的细节。 8. 工具支持 使用像JConsole、VisualVM这样的工具可以帮助开发者监控类加载情况,分析类加载器的行为,这对于诊断...

    ClassLoader

    - **自定义类加载器**则是通过重写`loadClass`方法来自定义类的加载过程。 ### 总结 本实例展示了如何通过自定义类加载器来加载类并实例化对象的过程。这种方法在某些特定场景下非常有用,比如在需要动态加载类的...

    Tomcat 5.0.18 ClassLoader source code insight

    此外,提供的两个PDF文件《Mehlhorn-Sanders-Toolbox.pdf》和《Data Structures and Algorithms.pdf》虽然与Tomcat的ClassLoader直接关联不大,但它们是关于数据结构和算法的重要参考资料。数据结构和算法是软件开发...

    JAVA 类加载机制分析

    Java提供两种动态加载类的方式:隐式加载(通过实例化类)和显式加载(使用`Class.forName()`或`ClassLoader.loadClass()`)。静态块(static block)的执行时机与类的加载密切相关,通常在类被首次加载或实例化时...

    Java的类加载器

    例如,`java.lang.ClassLoader`的`loadClass()`方法,以及其子类如`sun.misc.Launcher$AppClassLoader`的实现,可以帮助我们理解双亲委派模型的实现细节。 通过以上内容,我们可以了解到Java类加载器在Java程序运行...

    Java加载。jar包

    - **`findClass`**:在 JDK 1.2 之后,`loadClass` 方法会默认调用 `findClass` 来实现类的实际加载逻辑。如果自定义的 `ClassLoader` 没有正确实现 `findClass` 方法,则最终会由系统 `ClassLoader` 负责加载。 - *...

    Java SE: ClassLoader in depth

    1. loadClass(String name):加载名为name的类。它是一个受保护的方法,外界一般通过findClass方法间接调用。 2. findClass(String name):查找并返回名为name的类。这是一个受保护的方法,允许子类覆盖这个方法以...

    Java类加载器.pdf

    - 使用`ClassLoader.loadClass(String name)`方法显式加载类。 其中,`Class.forName()`方法有两种重载形式,第一个只接受类名作为参数,第二个允许控制是否初始化类以及指定类加载器。如果只使用一个参数的`Class...

    动态加载jar包的实现

    `CSClassLoaderUtil`可能是一个实现了`java.lang.ClassLoader`接口的类,它重写了`loadClass()`方法。这个方法通常用于根据类名查找并加载类。在自定义的类加载器中,我们可以编写代码来从特定的jar包中读取字节码,...

    译 Java类加载机制(二)

    类加载器通过`loadClass()`方法工作,它遵循双亲委派模型:当一个类加载器收到加载类的请求时,它首先会委托给父类加载器去尝试加载,只有当父类加载器无法加载时,当前类加载器才会尝试自己加载。 在实际开发中,...

    Java虚拟机JVM类加载初始化

    类加载器的层次结构包括引导类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和系统类加载器(App ClassLoader)。这些内置的类加载器加载的类在JVM生命周期中不会被卸载。而用户自定义的...

    深入了解JavaClassLoader,Bytecde.pdf

    - **loadClass**: 这是ClassLoader的核心方法,用于根据类名加载类。它有2个参数,一个是要加载的类名,另一个是一个布尔值,决定是否解析加载的类。 - **defineClass**: 这个方法将字节数组(通常从.class文件...

    深入理解Java中的类加载器.pdf

    - 创建自定义类加载器实例后,可以使用`loadClass`方法加载类,并通过`newInstance`方法创建类的实例。 - 示例: ```java NetworkClassLoader loader = new NetworkClassLoader("example.com", 8080); Object ...

    URLClassLoader中指定目录和jar的问题

    - 当`loadClass`方法被调用时,`URLClassLoader`会遍历其URL列表,查找指定类的`.class`文件。 3. **指定目录加载**: - 目录URL(如`file:/path/to/directory/`)用于加载目录下的类文件。类加载器会递归遍历...

    Java开发面试必备知识技能总结视频合集

    - **源码解读**:深入分析`ClassLoader`的核心代码,包括`loadClass`方法等关键部分,掌握类加载过程中的细节。 - **实战案例**:通过具体案例来演示如何利用`ClassLoader`解决实际问题,比如热部署等场景的应用。 ...

Global site tag (gtag.js) - Google Analytics