自定义类加载器,加载指定路径在D盘下的lib文件夹下的类。
步骤:
-
新建一个需要被加载的类Test.jave
-
编译Test.jave到指定lib目录
-
自定义类加载器HeroClassLoader继承ClassLoader:
- 重写findClass()方法
- 调用defineClass()方法
- 测试自定义类加载器
实现: (1)新建一个 Test.java 类,代码如下:
package com.hero.jvm.classloader;
public class Test {
public void say(){
System.out.println("Hello HeroClassLoader");
}
}
(2)使用 javac Test.java 命令,将生成的 Test.class 文件放到 D:/lib/com/hero/jvm/classloader 文件夹下。 (3)自定义类加载器,代码如下:
package com.hero.jvm.classloader;
import java.io.*;
public class HeroClassLoader extends ClassLoader {
private String classpath;
public HeroClassLoader(String classpath) {
this.classpath = classpath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
//输入流,通过类的全限定名称加载文件到字节数组
byte[] classDate = getData(name);
if (classDate != null) {
//defineClass方法将字节数组数据 转为 字节码对象
return defineClass(name, classDate, 0, classDate.length);
}
} catch (IOException e) {
e.printStackTrace();
}
return super.findClass(name);
}
//加载类的字节码数据
private byte[] getData(String className) throws IOException {
String path = classpath + File.separatorChar +
className.replace('.', File.separatorChar) + ".class";
try (InputStream in = new FileInputStream(path);
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
byte[] buffer = new byte[2048];
int len = 0;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
return out.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
有时候我们会有加载同名的类的需求,这是我们就需要打破双亲委派机制,需求自己写一个类加载器满足,首先创建一个自定义类加载器继承ClassLoader并重写findClass和loadClass方法:
public class CustomClassLoader extends ClassLoader{
private String classPath;
public CustomClassLoader(String classPath){
this.classPath=classPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] bytes=null;
int len=0;
//找到要加载的类的class文件路径,并读入字节码
try(FileInputStream fis=new FileInputStream(classPath+"/"+name.replace(".","/")+".class")){
len=fis.available();
bytes=new byte[len];
fis.read(bytes);
}catch (Exception e){
e.printStackTrace();
}
//调用本地方法加载
return defineClass(name, bytes,0, len);
}
@Override
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);
if (c == null) {
long t0 = System.nanoTime();
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
//如果是要自己加载的类就直接自己加载,打破双亲委派,如果是其他被引用到的或父类,则让parent加载
if(name.endsWith("xxx")){
c = findClass(name);
}else{
c=this.getParent().loadClass(name);//注意这里不能写super.loadClass,否侧会进入调用死循环
}
// 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(c);
}
return c;
}
}
}
(4)测试,代码如下:
package com.hero.jvm.classloader;
import java.lang.reflect.Method;
public class TestMyClassLoader {
public static void main(String []args) throws Exception{
//自定义类加载器的加载路径
HeroClassLoader hClassLoader = new HeroClassLoader("D:\\lib"); //包名+类名
Class c = hClassLoader.loadClass("com.hero.jvm.classloader.Test");
if(c!=null){
Object obj=c.newInstance();
Method method=c.getMethod("say", null);
method.invoke(obj, null);
System.out.println(c.getClassLoader().toString());
} }
}
输出结果如下: