第九篇 JVM核心机制之JVM运行和类加载全过程(四)
(1)从上面源码看出,调用loadClass时会先根据委派模型在父加载器中加载,如果加载失败,则会调用当前加载器的findClass来完成加载。
(2)因此我们自定义的类加载器只需要继承ClassLoader,并覆盖findClass方法,下面是一个实际例子,在该例中我们用自定义的类加载器去加载我们事先准备好的class文件。
1 /** 2 * 自定义文件系统类加载器 3 * 4 * @author Zhang XiaoDao 5 * 6 */ 7 public class FileSystemClassLoader extends ClassLoader{ 8 9 private String rootDir; 10 11 public FileSystemClassLoader(String rootDir) { 12 super(); 13 this.rootDir = rootDir; 14 } 15 16 @Override 17 protected Class<?> findClass(String name) throws ClassNotFoundException { 18 Class<?> c = findLoadedClass(name); 19 //应该要先查询有没有加载过这个类,如果已经加载,则直接返回这个类。如果没有加载,则返回新的类 20 if(c != null){ 21 return c; 22 }else{ 23 ClassLoader parent = this.getParent(); 24 c = parent.loadClass(name); 25 if(c != null){ 26 return c; 27 }else{ 28 byte[] classData = getClassData(name); 29 if(classData == null){ 30 throw new ClassNotFoundException(); 31 }else{ 32 c = defineClass(name, classData, 0, classData.length); 33 } 34 } 35 } 36 return c; 37 } 38 39 private byte[] getClassData(String classname){//com.bjsxt.test.User --> d:/java/ com/bjsxt/test/User.class 40 String path = rootDir + "/" + classname.replace('.', '/') + ".class"; 41 //IOUtils 可以使用它将流中的数据转成字节数组 42 InputStream is = null; 43 ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream(); 44 try { 45 is = new FileInputStream(path); 46 byte[] buffer = new byte[1024]; 47 int temp = 0; 48 while((temp= is.read(buffer))!=-1){ 49 baOutputStream.write(buffer, 0, temp); 50 } 51 return baOutputStream.toByteArray(); 52 } catch (Exception e) { 53 e.printStackTrace(); 54 return null; 55 }finally { 56 if(is != null){ 57 try { 58 is.close(); 59 } catch (IOException e) { 60 e.printStackTrace(); 61 } 62 } 63 if(baOutputStream != null){ 64 try { 65 baOutputStream.close(); 66 } catch (IOException e) { 67 e.printStackTrace(); 68 } 69 } 70 } 71 // return null; 72 } 73 74 }
1 /** 2 * 3 * 测试自定义加载器 4 * 5 * @author Zhang XiaoDao 6 * 7 */ 8 public class Demo03 { 9 public static void main(String[] args) throws ClassNotFoundException { 10 FileSystemClassLoader loader = new FileSystemClassLoader("d:/java"); 11 FileSystemClassLoader loader2 = new FileSystemClassLoader("d:/java"); 12 13 Class<?> c1 = loader.loadClass("com.zzp.user"); 14 Class<?> c2 = loader.loadClass("com.zzp.user"); 15 //同一个类被不同的加载器加载,jvm会认为是不同的类 16 Class<?> c3 = loader2.loadClass("com.zzp.user"); 17 Class<?> c4 = loader2.loadClass("java.lang.String"); 18 Class<?> c5 = loader2.loadClass("com.Demo01"); 19 20 21 System.out.println(c1); 22 System.out.println(c2); 23 System.out.println(c3.getClassLoader());//自定义类加载器 24 System.out.println(c4.getClassLoader());//引导类加载器 25 System.out.println(c5.getClassLoader());//系统类加载器 26 } 27 }
网络类加载器:
1 /** 2 * 网络类加载器 3 * 4 * @author Zhang XiaoDao 5 * 6 */ 7 public class NetClassLoader extends ClassLoader{ 8 9 private String rootUrl; 10 11 public NetClassLoader(String rootUrl) { 12 super(); 13 this.rootUrl = rootUrl; 14 } 15 16 @Override 17 protected Class<?> findClass(String name) throws ClassNotFoundException { 18 Class<?> c = findLoadedClass(name); 19 //应该要先查询有没有加载过这个类,如果已经加载,则直接返回这个类。如果没有加载,则返回新的类 20 if(c != null){ 21 return c; 22 }else{ 23 ClassLoader parent = this.getParent(); 24 c = parent.loadClass(name); 25 if(c != null){ 26 return c; 27 }else{ 28 byte[] classData = getClassData(name); 29 if(classData == null){ 30 throw new ClassNotFoundException(); 31 }else{ 32 c = defineClass(name, classData, 0, classData.length); 33 } 34 } 35 } 36 return c; 37 } 38 39 private byte[] getClassData(String classname){//com.bjsxt.test.User --> d:/java/ com/bjsxt/test/User.class 40 String path = rootUrl + "/" + classname.replace('.', '/') + ".class"; 41 //IOUtils 可以使用它将流中的数据转成字节数组 42 InputStream is = null; 43 ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream(); 44 try { 45 URL url = new URL(path); 46 is = url.openStream(); 47 byte[] buffer = new byte[1024]; 48 int temp = 0; 49 while((temp= is.read(buffer))!=-1){ 50 baOutputStream.write(buffer, 0, temp); 51 } 52 return baOutputStream.toByteArray(); 53 } catch (Exception e) { 54 e.printStackTrace(); 55 return null; 56 }finally { 57 if(is != null){ 58 try { 59 is.close(); 60 } catch (IOException e) { 61 e.printStackTrace(); 62 } 63 } 64 if(baOutputStream != null){ 65 try { 66 baOutputStream.close(); 67 } catch (IOException e) { 68 e.printStackTrace(); 69 } 70 } 71 } 72 // return null; 73 } 74 75 }