首页 > 编程 > Java > 正文

自定义 Java ClassLoader

2019-11-08 18:33:16
字体:
来源:转载
供稿:网友

首先看一下 java.lang.ClassLoader 方法 loadClass(String name) 方法的源码

public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false);}PRotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class c = findLoadedClass(name);//检查,class是否已经被加载过了,如果加载过了就不会再加载,防止重复加载。 if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false);//如果没有被加载,则交给父类 ClassLoader 进行加载,java的双亲委派类加载机制 } else { c = findBootstrapClassOrNull(name);//如果没有父类加载器,则 直接交给最顶层的 类加载器进行加载。 } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) {//如果父类加载器,也没有加载到,调用 findClass 方法。 // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name);//findClass 源码,见下面。 // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { /** * 关于方法 resolveClass 的解释 * Links the specified class. This (misleadingly named) method may be * used by a class loader to link a class. If the class <tt>c</tt> has * already been linked, then this method simply returns. Otherwise, the * class is linked as described in the "Execution" chapter of * <cite>The Java&trade; Language Specification</cite>. * </p> * * @param c * The class to link * * @throws NullPointerException * If <tt>c</tt> is <tt>null</tt>. * * @see #defineClass(String, byte[], int, int) */ resolveClass(c); } return c; }}//什么都没有,就是简单抛出一个 Exceptionprotected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name);}

通过分析源码,我们知道要自定义 ClassLoader 那么继承 ClassLoader 重写 findClass 方法就行了。

示例代码import java.io.ByteArrayOutputStream;import java.io.FileInputStream;import java.nio.ByteBuffer;import java.nio.channels.Channels;import java.nio.channels.FileChannel;import java.nio.channels.WritableByteChannel;public class MyClassLoader extends ClassLoader { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = null; try { byte[] data = getClassFileBytes(name); c = defineClass(name, data, 0, data.length);//name参数是要加载类的 package } catch (Exception e) { e.printStackTrace(); } return c; } private byte[] getClassFileBytes(String name) throws Exception { String path = "D://MyEclipse 10//jd-finance-platform//AtestJDK1-8//bin//"; String classPath = name.replace(".", "//") + ".class"; //class 文件的存放路径 String classFile = path + classPath; FileInputStream fis = new FileInputStream(classFile); FileChannel fileC = fis.getChannel(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); WritableByteChannel outC = Channels.newChannel(baos); ByteBuffer buffer = ByteBuffer.allocateDirect(1024); while (true) { int i = fileC.read(buffer); if (i == 0 || i == -1) { break; } buffer.flip(); outC.write(buffer); buffer.clear(); } fis.close(); return baos.toByteArray(); }}测试代码public class Test{ public static void main(String[] args) throws Exception{ MyClassLoader myc = new MyClassLoader(); Class<?> c = myc.loadClass("com.lp.jdk18.JDK18");//字符串是要加载类的 package Object obj = c.newInstance(); System.out.println(obj); System.out.println(obj.getClass().getClassLoader()); System.out.println(obj.getClass().getClassLoader().getParent()); }}输出结果com.lp.jdk18.JDK18@520b368fcom.lp.classload.MyClassLoader@77f2fbffsun.misc.Launcher$AppClassLoader@15b94ed3
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表