`

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原理

    ### Java ClassLoader原理详解 #### 摘要 本文探讨了Java虚拟机(JVM)中的一个重要特性:动态类加载(Dynamic Class Loading)。这一机制为Java平台提供了强大的能力,允许在运行时安装软件组件,例如从网络下载...

    webshpere classloader 原理

    ### WebSphere ClassLoader原理 #### 一、概述 在探讨WebSphere Application Server v6中的ClassLoaders之前,我们首先简要回顾一下ClassLoaders的基本概念及其在Java虚拟机(JVM)中的作用。 **ClassLoaders**是...

    Android 使用classloader原理进行热更新

    热更新通常依赖于类加载器(Classloader)的工作原理来实现,本篇文章将深入探讨如何利用Android的类加载器实现热更新的机制。 首先,我们需要理解什么是类加载器。在Java和Android中,类加载器是负责查找、加载和...

    Java classloader原理深究

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

    ClassLoader类加载机制和原理详解

    本文将深入探讨ClassLoader的工作原理和类加载机制,帮助开发者理解这个至关重要的概念。 1. 类加载机制概述 Java的类加载机制遵循“双亲委派模型”(Delegation Model)。当一个类被加载时,它首先会尝试由当前...

    classloader

    学习ClassLoader的工作原理以及如何创建自己的ClassLoader是必要的。 首先,让我们深入了解ClassLoader的基本概念。在传统编程语言中,如C或C++,程序通常是一个单一的可执行文件,而Java则不同,它的编译结果是以...

    自定义classloader的使用

    一、Classloader的工作原理 Java的类加载机制遵循双亲委派模型,即当一个类加载器需要加载类时,它首先委托父类加载器尝试加载,只有当父类加载器无法加载时,才会尝试自己加载。这种设计避免了类的重复加载,并...

    Java ClassLoader定制实例

    理解ClassLoader的工作原理以及如何定制它,对于深入学习Java的运行机制和进行高级应用开发具有重要意义。本篇文章将深入探讨Java ClassLoader的内部工作,并通过一个具体的实例来展示如何定制自己的ClassLoader。 ...

    ClassLoader 详解.doc

    深入理解ClassLoader的工作原理对于优化应用性能、解决类加载问题以及实现自定义加载策略至关重要。 首先,JVM启动时,会构建一个类加载器的层次结构,主要包括三个基本类加载器: 1. Bootstrap ClassLoader:引导...

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

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

    ClassLoader

    通过对`ClassLoader`的基本概念、工作原理、双亲委托机制以及不同类型的类加载器的了解,我们可以更好地理解Java类加载的过程及其背后的设计哲学。这对于深入理解Java虚拟机的内部机制以及开发高质量的应用程序都至...

    ClassLoader小例子

    本示例"ClassLoader小例子"将深入探讨这个概念,并通过一个具体的程序来演示其工作原理。下面我们将详细讨论ClassLoader的基本概念、工作流程以及如何自定义ClassLoader。 1. **ClassLoader的基本概念** - 类加载...

    java ClassLoader机制及其在OSGi中的应用

    理解ClassLoader的工作原理对于优化Java应用程序性能以及解决类冲突等问题具有重要意义。 一、ClassLoader的基本概念 Java程序由多个类组成,每个类对应一个.class文件。当程序运行时,ClassLoader根据需要动态...

    JVM ClassLoader简析

    本文将深入浅出地探讨JVM ClassLoader的工作原理和相关知识点。 首先,ClassLoader可以分为三种基本类型:Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader。Bootstrap ClassLoader是JVM...

    理解Java ClassLoader机制

    理解ClassLoader的工作原理对于优化应用性能、处理类加载问题以及实现自定义加载器至关重要。 首先,我们来了解一下ClassLoader的基本层次结构。在Java中,ClassLoader分为三个主要层次:Bootstrap ClassLoader、...

    jboss 5 原理 2 classloader

    JBoss 5是一款知名的Java应用服务器,其在类加载(Class Loading)方面有着独特的处理方式...通过理解和掌握JBoss 5的类加载原理,开发者可以更有效地管理和优化应用程序的运行时环境,提高软件的可扩展性和可维护性。

Global site tag (gtag.js) - Google Analytics