`

ClassLoader原理

阅读更多

最近本来打算研究分布式的东西的,看了一位大侠写的分布式系统,其中要实现把class传到客户端,然后在客户端实例化的工作,就去研究了一下ClassLoader的原理。

准备工作:http://download.java.net/openjdk/jdk6/

压缩包中含有 Windows, Linux, Solaris 平台 JRE 源代码、JVM 源代码,以及 JDK 中类库和工具的源代码。

 

有了源代码就可以查看源码分析了。

JVM自带的类加载器可以分为三类:Boot Start ClassLoader,Ext ClassLoader, App ClassLoader

1. Boot Start ClassLoader其实不是一个类,其实就是直接由JVM自身来加载,因此当类如果是Boot Start ClassLoader加载的话,就会返回null。

public static void getBootStartClass() {
		URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();

		for (int i = 0; i < urls.length; i++) {
			System.out.println(urls[i]);
		}
		 
}

 从运行结果可以看到加载的都是Java/jdk1.6.0_23/jre/lib/下面的jar包

2.Boot Start ClassLoader会加载sun.misc.Launcher类。其中Lancherer调用ExtClassLoader.getExtClassLoader();生成ExtClassLoader。可见下面源代码

public Launcher() {
        // Create the extension class loader
        ClassLoader extcl;
        try {
            extcl = ExtClassLoader.getExtClassLoader();
        } catch (IOException e) {
            throw new InternalError(
                "Could not create extension class loader");
        }

        // Now create the class loader to use to launch the application
        try {
            loader = AppClassLoader.getAppClassLoader(extcl);
        } catch (IOException e) {
            throw new InternalError(
                "Could not create application class loader");
        }

        // Also set the context class loader for the primordial thread.
        Thread.currentThread().setContextClassLoader(loader);

        // Finally, install a security manager if requested
        String s = System.getProperty("java.security.manager");
        if (s != null) {
            SecurityManager sm = null;
            if ("".equals(s) || "default".equals(s)) {
                sm = new java.lang.SecurityManager();
            } else {
                try {
                    sm = (SecurityManager)loader.loadClass(s).newInstance();
                } catch (IllegalAccessException e) {
                } catch (InstantiationException e) {
                } catch (ClassNotFoundException e) {
                } catch (ClassCastException e) {
                }
            }
            if (sm != null) {
                System.setSecurityManager(sm);
            } else {
                throw new InternalError(
                    "Could not create SecurityManager: " + s);
            }
        }
    }

 接下来我们看一下ExtClassLoader 类的源代码,可以看到继承了URLClassLoader类,加载的路径是系统属性java.ext.dirs。打印出来为:jdk1.6.0_23\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext

 static class ExtClassLoader extends URLClassLoader {
        private File[] dirs;

        /**
         * create an ExtClassLoader. The ExtClassLoader is created
         * within a context that limits which files it can read
         */
        public static ExtClassLoader getExtClassLoader() throws IOException
        {
            final File[] dirs = getExtDirs();

            try {
                // Prior implementations of this doPrivileged() block supplied
                // aa synthesized ACC via a call to the private method
                // ExtClassLoader.getContext().

                return (ExtClassLoader) AccessController.doPrivileged(
                     new PrivilegedExceptionAction() {
                        public Object run() throws IOException {
                            int len = dirs.length;
                            for (int i = 0; i < len; i++) {
                                MetaIndex.registerDirectory(dirs[i]);
                            }
                            return new ExtClassLoader(dirs);
                        }
                    });
            } catch (java.security.PrivilegedActionException e) {
                    throw (IOException) e.getException();
            }
        }

        void addExtURL(URL url) {
                super.addURL(url);
        }

        /*
         * Creates a new ExtClassLoader for the specified directories.
         */
        public ExtClassLoader(File[] dirs) throws IOException {
            super(getExtURLs(dirs), null, factory);
            this.dirs = dirs;
        }

        private static File[] getExtDirs() {
            String s = System.getProperty("java.ext.dirs");
            File[] dirs;
            if (s != null) {
                StringTokenizer st =
                    new StringTokenizer(s, File.pathSeparator);
                int count = st.countTokens();
                dirs = new File[count];
                for (int i = 0; i < count; i++) {
                    dirs[i] = new File(st.nextToken());
                }
            } else {
                dirs = new File[0];
            }
            return dirs;
        }
}

 再看看APP ClassLoader,也继承了URLClassLoader。加载的路径是系统属性java.ext.dirs

static class AppClassLoader extends URLClassLoader {

        public static ClassLoader getAppClassLoader(final ClassLoader extcl)
            throws IOException
        {
            final String s = System.getProperty("java.class.path");
            final File[] path = (s == null) ? new File[0] : getClassPath(s);

            // Note: on bugid 4256530
            // Prior implementations of this doPrivileged() block supplied
            // a rather restrictive ACC via a call to the private method
            // AppClassLoader.getContext(). This proved overly restrictive
            // when loading  classes. Specifically it prevent
            // accessClassInPackage.sun.* grants from being honored.
            //
            return (AppClassLoader)
                AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                    URL[] urls =
                        (s == null) ? new URL[0] : pathToURLs(path);
                    return new AppClassLoader(urls, extcl);
                }
            });
        }
}

 既然有那么多加载器,那么它们的加载顺序是怎么样的呢?从下面的代码可以看到当加载类的时候,会先看一下当前类是不是已经被加载了,如果加载了就返回。如果没,就调用父类的加载器来加载类。如果父类的类加载器是null就调用bootsttap classloader来加载。这就是父类委托,因此在加载的时候是先从bootsttap classloader开始查找,一层层往下找。

 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 = findBootstrapClass0(name);
                }
            } catch (ClassNotFoundException e) {
                // If still not found, then invoke findClass in order
                // to find the class.
                c = findClass(name);
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }

 看了那么多源代码那么怎么实现自己的classloader呢,有什么作用呢,对于一些我们不想被反编译的类,我们可以调用加密技术将类加密。在使用的时候只要用自定义的classloader反编译就好了。

我们可以通过两种方法来写自己的classloader,下面分别来介绍:

第一种是继承ClassLoader方法主要是用FileInputStream读取class,然后用defineClass方法返回class。注意在defineClass()方法的第一个参数必须设置成null。不然会抛出异常

 

package com.fnk.classloader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class FileClassLoader extends ClassLoader {
	private String directory = "C:/"; // Default directory.
	private String type = ".class";

	public FileClassLoader(String directory) {
		this.directory = directory;
	}

	public Class<?> findClass(String name) throws ClassNotFoundException {
		byte[] data;
		data = loadClassData(getFileName(name));
		return defineClass(name, data, 0, data.length);

	}
	
	private String getFileName(String className){
		int index = className.lastIndexOf(".");
		if(index != -1){
			return className.substring(index + 1);
		}else{
			return className;
		}
	}

	private byte[] loadClassData(String name) throws ClassNotFoundException {
		FileInputStream fis = null;
		ByteArrayOutputStream baos = null;

		try {
			fis = new FileInputStream(directory + name + type);
			baos = new ByteArrayOutputStream();
			int len = 0;
			while ((len = fis.read()) != -1) {
				baos.write(len);
			}
			byte[] data = baos.toByteArray();
			return data;
		} catch (Exception e) {
			e.printStackTrace();
			throw new ClassNotFoundException();
		} finally {
			if (fis != null)
				try {
					fis.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			if (baos != null)
				try {
					baos.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

		}
	}
	
	public static void main(String[] args) {
		FileClassLoader classLoader1 = new FileClassLoader(
				"./");
		try {
			Class c1 = classLoader1.loadClass("com.fnk.classloader.TestClass");
			Testf tc1 = (Testf)c1.newInstance();
			tc1.test();
	 
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}

 

第二种是 URLClassLoader 加载jar文件,然后调用loaderclass查找类。

 

package com.fnk.classloader;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class MyURLClassLoader {
	public static Class loaderClass(String file, String className) {
		URL url;
		Class myClass = null;
		try {
			url = new URL("file:" + file);
			URLClassLoader myClassLoader = new URLClassLoader(
					new URL[] { url }, Thread.currentThread()
							.getContextClassLoader());

			myClass = myClassLoader.loadClass(className);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return myClass;
	}

	public static void main(String[] args) {
		try {
			Testf testf = (Testf)loaderClass("./TestClass.jar",
					"com.fnk.classloader.TestClass").newInstance();
			testf.test();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

 附件中是自定义的classloader

 

分享到:
评论

相关推荐

    Java ClassLoader原理

    Sun 官方关于 ClassLoader原理的文章,值得一看

    webshpere classloader 原理

    详细说明了websphere classloader 的架构与实现

    Android 使用classloader原理进行热更新

    使用Android的classloader加载器实现热更新,通过反射机制获取到源码的Elements数组替换classes.dex实现更新,只能重启软件进行更新,无法实现实时更新。

    Java classloader原理深究

    前面已经写过一篇关于java classloader的拙文java classloader原理初探。  时隔几年,再看一遍,觉得有些地方显得太过苍白,于是再来一篇:  完成一个Java类之后,经过javac编译,会生成一个class文件,这个...

    ClassLoader类加载机制和原理详解

    ClassLoader类加载机制和原理详解

    Java ClassLoader 原理详细分析

    一、什么是ClassLoader?  大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程序的一个入口函数来调用系统的...

    【图解版】深入分析ClassLoader类加载工作机制

    【图解版】深入分析ClassLoader类加载工作机制,从原理到JVM的装载过程,详情分析了ClassLoader加载类以及自定义类加载器的过程,不可用于商业用途,如有版权问题,请联系删除!

    ClassLoader 详解.doc

    关于J2EE服务器的ClassLoader的原理,该文档清晰了揭示了jvm装载类的顺序,同时用户可以自定义修改classLoader的配置 通过该文档,可以加深对Java虚拟机的理解

    ClassLoader加载机制

    该电子书详细介绍了java虚拟机类加载机制,对于深入理解jvm工作原理有很好的帮助作用,对于初学java,有一定工作经验的小伙伴来说是一本提高自身java素养,夯实自己java基本技能的“葵花宝典”。

    jboss 5 原理 2 classloader

    JBoss has always had a unique way of dealing with classloading, and the new classloading layer that comes with Microcontainer is no exception (keep in mind that you can use Microcontainer without ...

    java自定义类加载classloader文档,包括代码

    java自定义类加载classloader文档,包括代码,以及详细的原理及过程

    Java_ClassLoader详解

    Java_ClassLoader详解,解说java类的加载的原理,让你轻松了解java的类加载

    论文研究-ClassLoader加密技术改进研究 .pdf

    ClassLoader加密技术改进研究,徐首泽,金瓯,ClassLoader加密技术是Java当中用的比较广泛的代码保护技术,本文分析了ClassLoader加密技术的原理,发现并分析了现有方法存在的漏洞,同�

    Java中ClassLoader类加载学习总结

    本篇文章主要给大家讲述了Java中ClassLoader类加载的原理以及用法总结,一起学习下。

    Java类加载原理解析

    Java类加载原理解析 classloader

    深入JVM内核 - 原理、诊断与优化

    详细介绍ClassLoader的原理和应用。分析2个案例,说明ClassLoader的使用。 第七课 性能监控工具 线程死锁分析 OOM分析 介绍常用的JVM诊断和分析工具,并以死锁和OOM为例,展示这些工具的使用。 第八课 分析Java...

    Java编程语言的基本原理.docx

    Java 编程语言的基本原理 Java 编程语言是当今最流行的编程语言之一,它的基本原理是确保 Java 程序可以跨平台运行的。为了实现这一点,Java 虚拟机(JVM)扮演着至关重要的角色。 一、Java 程序跨平台原理 Java ...

    06.JVM原理讲解和调优.pdf

    JVM 原理讲解和调优 JVM(Java Virtual Machine,Java 虚拟机)是 Java 语言的核心组件,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM 的主要功能是将 Java 字节码转换为...

Global site tag (gtag.js) - Google Analytics