文件类加载器
package com.lyy.test; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * 自定义文件系统加载器 * @author 01 * */ public class FileSystemClassLoader extends ClassLoader{ //com.lyy.test.User --> d:/myjava/com/lyy/test/User.class private String rootDir; public FileSystemClassLoader(String rootDir){ this.rootDir=rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); //首先查询是否加载过该类,如果已经加载过,直接返回已经加载好的类,否则加载新的类 if(null != c){ return c; }else{ ClassLoader parent = this.getParent(); c = parent.loadClass(name); //委派给父类加载 if(null != c){ return c; }else{ byte[] classData = getClassData(name); if(classData==null){ throw new ClassNotFoundException(); }else{ c = defineClass(name, classData,0, classData.length); } } } return c; } private byte[] getClassData(String name) { //com.lyy.test.User d:/myjava/com/lyy/test/User.class String path = rootDir+"/"+name.replace('.', '/')+"class"; //IOUtils,可以使用它将流中的数据转成字节数据 InputStream is = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { is = new FileInputStream(path); byte[] buffer = new byte[1024]; int temp = 0; while((temp=is.read(buffer)) != -1){ baos.write(buffer,0,temp); } return baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); return null; }finally{ try { if(is != null){ is.close(); } if(baos != null){ baos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
网络类加载器
package com.lyy.test; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; /** * 网络类加载器 * @author 01 * */ public class NetClassLoader extends ClassLoader{ //com.lyy.test.User --> www.baidu.com private String rootUrl; public NetClassLoader(String rootUrl){ this.rootUrl=rootUrl; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); //首先查询是否加载过该类,如果已经加载过,直接返回已经加载好的类,否则加载新的类 if(null != c){ return c; }else{ ClassLoader parent = this.getParent(); c = parent.loadClass(name); //委派给父类加载 if(null != c){ return c; }else{ byte[] classData = getClassData(name); if(classData==null){ throw new ClassNotFoundException(); }else{ c = defineClass(name, classData,0, classData.length); } } } return c; } private byte[] getClassData(String name) { //com.lyy.test.User d:/myjava/com/lyy/test/User.class String path = rootUrl+"/"+name.replace('.', '/')+"class"; //IOUtils,可以使用它将流中的数据转成字节数据 InputStream is = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { URL url = new URL(path); is = url.openStream(); byte[] buffer = new byte[1024]; int temp = 0; while((temp=is.read(buffer)) != -1){ baos.write(buffer,0,temp); } return baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); return null; }finally{ try { if(is != null){ is.close(); } if(baos != null){ baos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
加密解密加载器(取反操作,DES对称加密解密)
package com.lyy.test; /** * 测试简单加密解密(取反)操作 * @author 01 * */ public class Demo4 { public static void main(String[] args) throws Exception { //测试取反操作 // int a = 3;//0000011 // System.out.println(Integer.toBinaryString(a^0xff)); //加密后的class文件,正常的类加载器无法加载,报clasformatError // FileSystemClassLoader load = new FileSystemClassLoader("E:/VIP/temp"); // Class<?> c = load.loadClass("HelloWrold"); // System.out.println(c); DecrptClassLoader loader = new DecrptClassLoader("E:/VIP/temp"); Class<?> c = loader.loadClass("com.lyy.temp.HelloWrold"); System.out.println(c); } }
package com.lyy.test; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * 自定义文件系统加载器 * @author 01 * */ public class FileSystemClassLoader extends ClassLoader{ //com.lyy.test.User --> d:/myjava/com/lyy/test/User.class private String rootDir; public FileSystemClassLoader(String rootDir){ this.rootDir=rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); //首先查询是否加载过该类,如果已经加载过,直接返回已经加载好的类,否则加载新的类 if(null != c){ return c; }else{ ClassLoader parent = this.getParent(); c = parent.loadClass(name); //委派给父类加载 if(null != c){ return c; }else{ byte[] classData = getClassData(name); if(classData==null){ throw new ClassNotFoundException(); }else{ c = defineClass(name, classData,0, classData.length); } } } return c; } private byte[] getClassData(String name) { //com.lyy.test.User d:/myjava/com/lyy/test/User.class String path = rootDir+"/"+name.replace('.', '/')+"class"; //IOUtils,可以使用它将流中的数据转成字节数据 InputStream is = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { is = new FileInputStream(path); byte[] buffer = new byte[1024]; int temp = 0; while((temp=is.read(buffer)) != -1){ baos.write(buffer,0,temp); } return baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); return null; }finally{ try { if(is != null){ is.close(); } if(baos != null){ baos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
package com.lyy.test; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * 加载文件系统加密后的class字节码的类加载器 * @author 01 * */ public class DecrptClassLoader extends ClassLoader{ //com.lyy.test.User --> d:/myjava/com/lyy/test/User.class private String rootDir; public DecrptClassLoader(String rootDir){ this.rootDir=rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); //首先查询是否加载过该类,如果已经加载过,直接返回已经加载好的类,否则加载新的类 if(null != c){ return c; }else{ ClassLoader parent = this.getParent(); c = parent.loadClass(name); //委派给父类加载 if(null != c){ return c; }else{ byte[] classData = getClassData(name); if(classData==null){ throw new ClassNotFoundException(); }else{ c = defineClass(name, classData,0, classData.length); } } } return c; } private byte[] getClassData(String name) { //com.lyy.test.User d:/myjava/com/lyy/test/User.class String path = rootDir+"/"+name.replace('.', '/')+"class"; //IOUtils,可以使用它将流中的数据转成字节数据 InputStream is = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { is = new FileInputStream(path); int temp = -1; while((temp=is.read()) != -1){ baos.write(temp^0xff); //取反操作,相当于解密操作 } return baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); return null; }finally{ try { if(is != null){ is.close(); } if(baos != null){ baos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
线程上下文类加载器
双亲委托机制以及类加载器的问题
一般情况下,保证同一个类中所关联的其他类都是由当前类的类加载器所加载的。
比如,Class本身在Ext下找到,那么他里面new出来的一些类也就只能用ext去查找了(不会低一个级别),所以有些明明app可以找到的,却找不到了。
JDBC API 他有实习那的driven部门(mysql/sql server),我们的JDBC API都是由Boot或者Ext来载入的,但是Service Prover却是由EXT或者App来载入,那么就有可能找不到driver了,在java领域中,其实只要分成这种Api-SPI(Service Provide Interface,特定厂商提供)的,都会遇到此问题。
常见的SPi 有JDBC、JCE、JNXP和JBI等。
package com.lyy.test; /** * 线程上下文类加载器 * @author 01 * */ public class Demo5 { public static void main(String[] args) throws Exception { ClassLoader loader = Demo5.class.getClassLoader(); System.out.println(loader); ClassLoader laoder2 = Thread.currentThread().getContextClassLoader(); System.out.println(laoder2); Thread.currentThread().setContextClassLoader(new FileSystemClassLoader("E:/VIP/")); System.out.println(Thread.currentThread().getContextClassLoader()); Class<Demo1> c = (Class<Demo1>)Thread.currentThread().getContextClassLoader().loadClass("com.lyy.test.Demo1"); System.out.println(c); System.out.println(c.getClassLoader()); } }