首先看一下 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™ 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;
}
}
//什么都没有,就是简单抛出一个 Exception
protected 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@520b368f
com.lp.classload.MyClassLoader@77f2fbff
sun.misc.Launcher$AppClassLoader@15b94ed3