标签:
java类加载器主要分为如下几种:
类加载器负责将java字节码文件加载到虚拟机内存中也就是类的生命周期的装载过程。(如下为类的生命周期)
下面是用户自定义类加载器的实现过程及代码:
实现一个用户自定义类加载器需要去继承ClassLoader类并重写findClass方法,代码如下
package com.space; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; public class MyClassLoader extends ClassLoader { private String path="/home/luciel/"; //默认加载路径 private String name; //类加载器名称 private final String filetype=".class"; //文件类型 public MyClassLoader(String name) { // TODO Auto-generated constructor stub super(); this.name=name; } public MyClassLoader(ClassLoader parent,String name){ super(parent); this.name=name; } @Override public Class<?> findClass(String name) throws ClassNotFoundException { // TODO Auto-generated method stub byte[] b=loadClassData(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassData(String name) { byte[] data=null; InputStream in=null; name=name.replace(‘.‘, ‘/‘); ByteArrayOutputStream out=new ByteArrayOutputStream(); try { in=new FileInputStream(new File(path+name+filetype)); int len=0; while(-1!=(len=in.read())){ out.write(len); } data=out.toByteArray(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { in.close(); out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return data; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } @Override public String toString() { // TODO Auto-generated method stub return this.name; } }
public MyClassLoader(String name) { // TODO Auto-generated constructor stub super(); this.name=name; }
这个构造方法中去调用ClassLoader无参构造方法从ClassLoader源码中可以得出:调用此构造方法会让系统类加载器成为该类加载器的父加载器。(注意:此处父类加载器不一定是继承关系,只是一种包装关系)。
在重写findClass方法时参照java API中实现一个网络类加载器的例子,API例子如下:
class NetworkClassLoader extends ClassLoader { String host; int port; public Class findClass(String name) { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassData(String name) { // load the class data from the connection . . . } }
下面是测试类以及main方法类的测试代码:
1 package com.space; 2 3 public class Color { 4 public Color() { 5 // TODO Auto-generated constructor stub 6 System.out.println("Color is loaded by "+this.getClass().getClassLoader()); 7 8 } 9 }
1 package com.space; 2 3 public class Red extends Color{ 4 5 public Red() { 6 // TODO Auto-generated constructor stub 7 System.out.println("Red is loaded by "+this.getClass().getClassLoader()); 8 9 } 10 11 }
1 package com.space; 2 3 public class TestMyClassLoader { 4 5 public static void main(String[] args) throws Exception { 6 7 MyClassLoader loader1=new MyClassLoader("loader1"); 8 9 loader1.setPath("/home/luciel/test1/"); 10 11 MyClassLoader loader2=new MyClassLoader(loader1, "loader2"); 12 13 loader2.setPath("/home/luciel/test2/"); 14 15 MyClassLoader loader3=new MyClassLoader(null, "loader3"); 16 17 loader3.setPath("/home/luciel/test3/"); 18 19 loadClassByMyClassLoader("com.space.Red",loader2); 20 21 loadClassByMyClassLoader("com.space.Red",loader3); 22 } 23 24 private static void loadClassByMyClassLoader(String name,ClassLoader loader) throws Exception{ 25 26 Class<?> c=loader.loadClass(name); 27 Object obj=c.newInstance(); 28 } 29 30 }
按照main方法中给三个类加载器传入的路径创建相应的环境并将com.space.Red、com.space.Color的class类拷贝到
/home/luciel/test1/和/home/luciel/test2/以及/home/luciel/test3/目录中去将com.space.TestMyClassLoader类和com.space.MyClassLoader拷贝
/home/luciel/main/ 中去并在该目录下执行
最终运行结果如下显示:
[root@localhost main]# java com.space.TestMyClassLoader
Color is loaded by loader1
Red is loaded by loader1
Color is loaded by loader3
Red is loaded by loader3
loadClassByMyClassLoader("com.space.Red",loader2);
如测试代码中 我们调用了loader2去加载Red类但Red类却打印出由loader1加载,这是由于类加载器秉承的是父委托机制loader2在创建时包装了loader1为其父类加载器,而loader1创建时由于调用的是没有传入父类加载器的构造方法,因此它的父加载器为系统类加载器。因此几个加载器的关系如下:
由于loader1的路径下有Red类class文件所以loader1可以加载,因此载Red类构造方法中打印的类加载器为loader1.
我门看似只去加载了Red类但运行结果却将Color父类加载了,而且Color类的加载在Red类之前,那是由于Red类主动使用 了Color类,因此在初始化Red类之前必须先初始化Color类,要初始化就必须先加载,所以先打印出了Color类的输出信息。(关于类的主动使用大家如果不清楚可以查查,一共有6种)
loadClassByMyClassLoader("com.space.Red",loader3);
再分析第二个测试代码,由于loader3创建时传入的父类加载器为 null,看下面关于ClassLoader类源码部分代码或查看java API
/** * Returns the parent class loader for delegation. Some implementations may * use <tt>null</tt> to represent the bootstrap class loader. This method * will return <tt>null</tt> in such implementations if this class loader‘s * parent is the bootstrap class loader. * * <p> If a security manager is present, and the invoker‘s class loader is * not <tt>null</tt> and is not an ancestor of this class loader, then this * method invokes the security manager‘s {@link * SecurityManager#checkPermission(java.security.Permission) * <tt>checkPermission</tt>} method with a {@link * RuntimePermission#RuntimePermission(String) * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify * access to the parent class loader is permitted. If not, a * <tt>SecurityException</tt> will be thrown. </p> * * @return The parent <tt>ClassLoader</tt> * * @throws SecurityException * If a security manager exists and its <tt>checkPermission</tt> * method doesn‘t allow access to this class loader‘s parent class * loader. * * @since 1.2 */ @CallerSensitive public final ClassLoader getParent() { if (parent == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkClassLoaderPermission(parent, Reflection.getCallerClass()); } return parent; }
getParent方法的说明如下部分文字:
* Returns the parent class loader for delegation. Some implementations may * use <tt>null</tt> to represent the bootstrap class loader. This method * will return <tt>null</tt> in such implementations if this class loader‘s * parent is the bootstrap class loader.
意思是说我们可以使用null表示 the bootstrap class loader(根类加载器)
那么loader3的父类加载器就是 根类加载器 ,而根类加载器只会去加载那些系统核心类库,显然我们的Red和Color类不属于此范围,而就只能让loader3加载,loader3的加载路径下有这两个类对应的字节码可以成功加载,所以大引出Red和Color类的类加载器为loader3
以上是自己最近在学习jvm时有关类加载器的相关知识总结。
标签:
原文地址:http://www.cnblogs.com/punisher/p/4393482.html