自定义类加载器MyClassLoader
package com.dwz.classLoader.chapter2; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class MyClassLoader extends ClassLoader{ private final static String DEFAULT_DIR = "C:\Users\Administrator\Desktop\classloader1"; private String dir = DEFAULT_DIR; private String classLoaderName; public MyClassLoader() { super(); } public MyClassLoader(String classLoaderName) { super(); this.classLoaderName = classLoaderName; } public MyClassLoader(String classLoaderName, ClassLoader parent) { //父委托 super(parent); this.classLoaderName = classLoaderName; } /** * @param name (xxx.xxx.xxx.xxx) * xxx/xxx/xxx/xxx.class */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String classPath = name.replaceAll("\.", "/"); File classFile = new File(dir, (classPath + ".class")); if(!classFile.exists()) { throw new ClassNotFoundException("The class " + name + " not found under " + dir); } byte[] classBytes = loadClassBytes(classFile); if(null == classBytes || classBytes.length == 0) { throw new ClassNotFoundException("load the class " + name + " failed"); } return this.defineClass(name, classBytes, 0, classBytes.length); } private byte[] loadClassBytes(File classFile) { try(ByteArrayOutputStream baos = new ByteArrayOutputStream(); FileInputStream fis = new FileInputStream(classFile)) { byte[] buffer = new byte[1024]; int len; while((len = fis.read(buffer)) != -1) { baos.write(buffer, 0, len); } baos.flush(); return baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); return null; } } public String getDir() { return dir; } public void setDir(String dir) { this.dir = dir; } public String getClassLoaderName() { return classLoaderName; } }
需要加载的目标类
package com.dwz.classLoader.chapter2; public class MyObject { static { System.out.println("My Object static block."); } public String hello() { return "Hello World!"; } }
测试一:
1.类加载器的委托是优先交给父加载器先去尝试加载
2.父加载器和子加载器其实是一种包装关系,或者包含关系
MyClassLoader classLoader1 = new MyClassLoader("MyClassLoader-1"); Class<?> loadClass = classLoader1.loadClass("com.dwz.classLoader.chapter2.MyObject"); System.out.println(loadClass); System.out.println(loadClass.getClassLoader()); Object obj = loadClass.newInstance(); Method method = loadClass.getMethod("hello", new Class<?>[] {}); Object result = method.invoke(obj, new Object[] {}); System.out.println(result);
1.先将自动编译好的MyObject.class复制到我们自定义的类加载器文件 DEFAULT_DIR 中
2.删除自动编译好的MyObject.class文件
测试二:
package com.dwz.classLoader.chapter2; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 1.类加载器的委托是优先交给父加载器先去尝试加载 * 2.父加载器和子加载器其实是一种包装关系,或者包含关系 */ public class MyClassLoaderTest { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { MyClassLoader classLoader1 = new MyClassLoader("MyClassLoader-1"); MyClassLoader classLoader2 = new MyClassLoader("MyClassLoader-2", classLoader1); Class<?> loadClass = classLoader2.loadClass("com.dwz.classLoader.chapter2.MyObject"); System.out.println(loadClass); System.out.println(((MyClassLoader)loadClass.getClassLoader()).getClassLoaderName()); } }
父委托机制:
1.定义类加载器
2.初始化类加载器
3.父子类加载器之间的真实关系--包装关系(包含关系)
4.父委托机制的优点是能够提高系统的安全性,在此机制下,用户自定义的类加载器不可能加载应该有父加载器加载的可靠类,
因此可以防止恶意的代码代替父加载器的可靠代码