classloader 加载类

Classloader 用到的的jvm 结构

classloader 加载类

classloader 加载类

类加载器的工作原理基于三个机制

1 委托

classloader 加载类

类加载器一共有三种

  1. bootstrap classloader:引导类加载器,加载rt.jar中的类,主要加载是java 类库
  2. sun.misc.Launcher$ExtClassLoader:扩展类加载器,加载lib/ext目录下的类;主要加载是java 的扩展类库
  3. classloader 加载类
  4. sun.misc.Launcher$AppClassLoader:系统类加载器,加载CLASSPATH下的类,即我们写的类,以及第三方提供的类

 

2 可见性

子类加载器加载类父类是不能看见的

根据可见性机制,子类加载器可以看到父类加载器加载的类,而反之则不行

3 单一性

 

1 判断findLoadedClass()方法返回的是否为null,如果不是null那么直接返回,这可以避免同一个类被加载两次;
2 如果findLoadedClass()返回的是null,那么就启动代理模式(委托机制),即调用上级的c方法,获取上级的方法是getParent(),当然上级可能还有上级,这个动作就一直向上走;
3 如果getParent().loadClass()返回的不是null,这说明上级加载成功了,那么就加载结果;
4 如果上级返回的是null,这说明需要自己出手了,这时loadClass()方法会调用本类的findClass()方法来加载类;
5 这说明我们只需要重写ClassLoader的findClass()方法,这就可以了!如果重写了loadClass()方法覆盖了代理模式!

OK,通过上面的分析,我们知道要自定义一个类加载器,只需要继承ClassLoader类,然后重写它的findClass()方法即可。那么在findClass()方法中我们要完成哪些工作呢?

  1. 找到class文件,把它加载到一个byte[]中;
  2. 调用defineClass()方法,把byte[]传递给这个方法即可

自定义加载器同理

 

findLoadedClass()---null---(代理模式委托机制)---调用每一个上级的

 

loadclass--找到了加载类的上级以后---findclass()

FileSystemClassLoader

public class FileSystemClassLoader extends ClassLoader {

    private String classpath;// 这是它的地盘!因为类加载器都是片警,它需要有自己的地盘!

   

    public FileSystemClassLoader() {}

 

    // FileSystemClassLoader创建类加载器时,就要为其指定负责的地盘!它只会到这里去查找类!

   

    public FileSystemClassLoader(String classpath) {

       this.classpath = classpath;

    }

   

    @Override

    public Class<?> findClass(String name) throws ClassNotFoundException {

       try {

            //通过类名称找到.class文件,把文件加载到一个字节数组中。

           byte[] datas = getClassData(name);

 

           if(datas == null) {

//如果返回的字节数组为null,说明没有找到这个类,抛出异常

              throw new ClassNotFoundException("类没有找到:" + name);

           }

           return this.defineClass(name, datas, 0, datas.length);

// this.defineClass(name, datas, 0, datas.length);

它可以把字节数组变成Class对象!defineClass()是ClassLoader的方法,它的作用是把字节数组变成Class对象!

 

       } catch (IOException e) {

           e.printStackTrace();

           throw new ClassNotFoundException("类找不到:" + name);

       }

    }

 

    private byte[] getClassData(String name) throws IOException {

       name = name.replace(".", "\\") + ".class";

       File classFile = new File(classpath, name);

       return FileUtils.readFileToByteArray(classFile);

// FileUtils commons-io.jar中的类

 

    }

}

       ClassLoader loader = new FileSystemClassLoader("F:\\classpath");

       Class clazz = loader.loadClass("cn.itcast.utils.CommonUtils");

       Method method = clazz.getMethod("md5", String.class);

       String result = (String) method.invoke(null, "qdmmy6");

       System.out.println(result);

 

当Abc.class已经被Application类加载器加载过了,然后如果想要使用Extension类加载器加载这个类,将会抛出java.lang.ClassNotFoundException异常。

4 Tomcat的类加载器

Tomcat会为每个项目提供一个类加载器,Tomcat提供的类加载器负责加载自己项目下的类,即WEB-INF\lib和WEB-INF\classes下的类。但Tomcat提供的类加载器不会使用传统的代理模式,而是自己先去加载,如果加载不到,再使用代理模式。

Tomcat提供的类加载器有这样一个好处,就是可以使自己项目下的类优先被加载!

classloader 加载类