自定义类加载器

  为什么需要自定义类加载器?java提供的类加载器只能够到指定的目录完成相关类的加载,若我们想对自定义目录下的类完成加载,此时就需要自定义类加载器。

  之前说过,类加载的过程中最后,执行到最后会调用ClassLoader的loadClass方法,那么我们可以通过自定义加载器继承ClassLoader类,使自定义的类加载器也具有loadClass方法,则调用自定义加载器的loadClass方法后也会遵循双亲委派机制,完成类的一系列传递加载过程(向上再向下)。又因为loadClass方法中的findClass方法并没有具体实现,我们继承的该方法当然也需要重写。总之,若我们不想打破既定的双亲委派机制,则只需要重写findClass方法即可。具体代码如下所示:
  

 1 static class MyClassLoader extends ClassLoader {
 2         private String rootDir;/*自定义类加载的查找class的路径*/
 3 
 4         /*指定该类加载器会查找的rootDir目录,和父加载器*/
 5         public MyClassLoader(String rootDir, ClassLoader parent){
 6             super(parent);
 7             this.rootDir = rootDir;
 8 
 9         }
10 
11         /*指定该类加载器会查找的rootDir目录*/
12         public MyClassLoader(String rootDir){
13             this.rootDir = rootDir;
14         }
15 
16 
17         @Override
18         protected Class<?> findClass(String name) ;
19         }

  第一步:创建路径作为成员变量,生成对应的构造方法。

  第二部:重写findClass方法。该方法具体实现如下:(主要为两步,先将class文件读取到字节数组中,使用defineClass方法完成类的加载过程)

protected Class<?> findClass(String name) throws ClassNotFoundException {
            //<1>.根据类的全路径(包含包名)类名和放置的目录确定类文件的路径
            String className = name.substring(name.lastIndexOf(".")+1)+ ".class";
            String classFile = rootDir  + className;

            FileInputStream fileInputStream = null;
            byte[] classData = null;
            try {
                //<2>.将class文件读取到字节数组
                fileInputStream = new FileInputStream(new File(classFile));//与class文件进行关联
                classData = new byte[fileInputStream.available()];//开辟一个与class文件等大小的字节数组用于读取
                fileInputStream.read(classData,0,classData.length);//将字节码读入字节数组
                //<3>.将字节数据创建一个class
                return defineClass(name,classData,0,classData.length);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (fileInputStream != null){
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            //<4>如果父类加载器不是自定义的,上面的加载过程没加载成功,则此调用会throw ClassNotFoundException
            return super.findClass(name);
        }

  第三步:编写测试方法

 public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
            String rootDir = "D:/class/";
            MyClassLoader classLoader = new MyClassLoader(rootDir);
            Class c = classLoader.loadClass("Person");
            Object object = c.newInstance();
            Method getNameMethod = c.getMethod("getName");
            Method getAgeMethod = c.getMethod("getAge");
            System.out.println("name:" + getNameMethod.invoke(object) + ",age:" + getAgeMethod.invoke(object));
            System.out.println("类加载器为:" + object.getClass().getClassLoader());

        }

  运行结果如图所示:

posted @ 2021-04-13 17:02  我不认识CBW  阅读(493)  评论(0编辑  收藏  举报