`
zy19982004
  • 浏览: 654508 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
博客专栏
F6f66edc-1c1a-3859-b76b-a22e740b7aa7
Hadoop学习
浏览量:249926
社区版块
存档分类
最新评论

Java ClassLoader学习二:ClassLader源码

 
阅读更多

一.ClassLoader源码继承图

 

      SecureClassLoader:这个类我没做深入研究,你把它当成一个增强版的ClassLoader,增强了从何地load class,增强了能不能load这些代码权限。

 

二.源码

 

public abstract class ClassLoader {

	// 父ClassLoader
	private ClassLoader parent;

	// 被此classLoader加载过的Class对象
	private Vector classes = new Vector();
	
	// The packages defined in this class loader.  Each package name is mapped
    // to its corresponding Package object.
    private HashMap packages = new HashMap();

	// 由虚拟机调用
	void addClass(Class c) {
		classes.addElement(c);
	}

	// The packages defined in this class loader. Each package name is mapped
	// to its corresponding Package object.
	private final HashMap<String, Package> packages = new HashMap<String, Package>();

	// 指明parent
	protected ClassLoader(ClassLoader parent) {
		this(checkCreateClassLoader(), parent);
	}

	// 不指名parent时使用SystemClassLoader
	protected ClassLoader() {
		this(checkCreateClassLoader(), getSystemClassLoader());
	}

	// 默认resolve=false
	public Class<?> loadClass(String name) throws ClassNotFoundException {
		return loadClass(name, false);
	}

	protected synchronized Class<?> loadClass(String name, boolean resolve)
			throws ClassNotFoundException {
		// 1 检查此class是否被此classloader加载过,
		// 最终是有native方法返回,native方法会使用到classes集合
		Class c = findLoadedClass(name);
		// 1.1 未被加载
		if (c == null) {
			try {
				// 1.1.1 此classloader有parent,委托parent去load
				if (parent != null) {
					c = parent.loadClass(name, false);
				} else {// 1.1.2 此classloader无parent = 启动类装载器去加载
					c = findBootstrapClassOrNull(name);
				}
			} catch (ClassNotFoundException e) {
			}
			// 如果没有找到class,自己去加载试试
			if (c == null) {
				c = findClass(name);
			}
		}
		// 找到的Class对象是否需要连接操作
		if (resolve) {
			resolveClass(c);
		}
		// 1.2 被加载过,直接返回
		return c;
	}

	protected final Class<?> findLoadedClass(String name) {
		if (!checkName(name))
			return null;
		return findLoadedClass0(name);
	}

	// 如果name里包含/,或者虚拟机不支持class数组你使用了数组的时候返回false,其它情况返回true,包括空的name
	// eg com.jyz.component.core.collection.Tuple return true
	private boolean checkName(String name) {
		if ((name == null) || (name.length() == 0))
			return true;
		if ((name.indexOf('/') != -1)
				|| (!VM.allowArraySyntax() && (name.charAt(0) == '[')))
			return false;
		return true;
	}

	// 检查package是否可访问
	private void checkPackageAccess(Class cls, ProtectionDomain pd) {
		final SecurityManager sm = System.getSecurityManager();
		if (sm != null) {
			// ...
		}
		domains.add(pd);
	}

	// 自定义classloader时重写此方法
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		throw new ClassNotFoundException(name);
	}

	// 将byte数组转换成一个Class对象,最终有native方法实现
	// 同一个byte数组,被不同的classloader加载,产生两个不同的Class对象
	protected final Class<?> defineClass(String name, byte[] b, int off, int len)
			throws ClassFormatError {
		return defineClass(name, b, off, len, null);
	}

	/*
	 * Determine protection domain, and check that: - not define java.* class, -
	 * signer of this class matches signers for the rest of the classes in
	 * package.
	 */
	//native的defineClass时会调用此方法检查name是否合法
	//首先checkName,然后还需要!name.startsWith("java.")
	//所以我们定义了java.mypackage包,都将异常
	//java.lang.SecurityException: Prohibited package name: java.mypackage
	private ProtectionDomain preDefineClass(String name,
			ProtectionDomain protectionDomain) {
		if (!checkName(name))
			throw new NoClassDefFoundError("IllegalName: " + name);
		if ((name != null) && name.startsWith("java.")) {
			throw new SecurityException("Prohibited package name: "
					+ name.substring(0, name.lastIndexOf('.')));
		}
		//...
	}

	// protected的resolveClass方法,可以在自定义的classloader调用
	protected final void resolveClass(Class<?> c) {
		resolveClass0(c);
	}
	
	//获得appClassLoader,实际调用Launcher完成
	public static ClassLoader getSystemClassLoader() {
		sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
		return l.getClassLoader();
    }

}

 

 

三.源码说明 

  1.  loadClass这个类是重点。
      1. 检查此class是否被此classloader加载过,有直接返回此class
      2. 检查此ClassLoader有无parent,有委托parent去load。无说明此CassLoader为ExtClassLoader,交给BootstrapLoader去加载。其实可以说委托parent去加载
      3. 某个ClassLoaer的parent并未加载到指定class,自己findClass(String name)去加载。
      4. 最后判断找到的Class对象是否需要连接操作并执行。
  2. 自定义classloader时重写findClass(String name)。
  3. ClassLoader.etSystemClassLoader()实际由sun.misc.Launcher去完成。
  4. ClassLoader构造函数里,不指名parent的话使用AppClassLoader。

 

 

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics