java classloader说明

1、Classloader的作用

1.1、Classloader加载类

classloader加载类后并把类型信息保存到方法区后,会创建一个Class对象(class的元数据
),存放在堆区的

1.2、确保class类唯一性
  • 类加载器
  • 类名
    识别方式: ClassLoader Instance id+PackageName+ClassName

2、Classloader加载机制

2.1、 Classloader的双亲委派加载机制
image.png
  • 加载jvm的类由BootstrapClassLoader
  • 加载jvm扩展类由ExtClassLoader
  • 加载CLASSPATH下的类使用AppClassLoader

源代码如下: ClassLoader的loadClass方法保证了双亲委派机制,先从父类中加载,再从子类中加载

    package java.lang.ClassLoader;

    import ....

     protected Class loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {
                // First,在虚拟机内存中查找是否已经加载过此类...类缓存的主要问题所在!!! 
                Class c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        if (parent != null) {
                   //先让上一层加载器进行加载
                            c = parent.loadClass(name, false);
                        } else {
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if class not found
                        // from the non-null parent class loader
                    }

                    if (c == null) {
                //调用此类加载器所实现的findClass方法进行加载
                        c = findClass(name);
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
2.2、 自定义Classloader
2.1、classloader的方法说明
名称 说明 备注
findClass(String name) 查找类,如果不想破坏双亲委派机制,可以重写该类
loaderClass(String name) 查找类,重写该方法会破坏双亲委派的加载机制,也可以代码层面保证不破坏
findLoadedClass(String name) 确定类是否加载
definclass(String name, byte[] b, int off, int len) 返回类

在加载指定路径包时破坏双亲委派加载机制,是为了解决包冲突问题

package com.tianzehao.test;

import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

public class ClassTest1 extends ClassLoader {

    private String libJarPath="";
    public ClassTest1(String filename) {
        super(ClassTest1.class.getClassLoader());
        this.libJarPath = filename;
    }

    @Override
    public Class loadClass(String name) throws ClassNotFoundException {
        JarInputStream jarInput =null;
        String resName = name.replace(".", "/") + ".class";
        if(name.startsWith("com.tianzehao")){
            try {
                InputStream fileInputStream = new FileInputStream(libJarPath);
                try {
                    jarInput = new JarInputStream(fileInputStream);
                    JarEntry entry = null;
                    while ((entry = jarInput.getNextJarEntry()) != null) {
                        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                        int chunk = 0;
                        byte[] data = new byte[256];
                        if( entry.getName().equals(resName)){
                            while (-1 != (chunk = jarInput.read(data))) {
                                bytes.write(data, 0, chunk);
                            }
                            byte[] tmpByte = bytes.toByteArray();
                            return defineClass(name,tmpByte,0,tmpByte.length);
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }

        return super.loadClass(name);
    }
}
2.3、 自定义Classloader说明

自定义classloader加载机制不在双亲委派之列,即父类是用自定义classloader,子类不会自动使用自定义classloader加载,需要自己通过classloader加载
如果一个包中依赖另一个类(AppClassLoader父类无法加载的包)需要都用自定义ClassLoader进行加,不然找不到包
demo

package com.tianzehao.test;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;

public class App {
    public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        String path =  System.getProperty("user.dir") + File.separator + "asd" +  File.separator + "javaTest-1.0-SNAPSHOT.jar";
        String path1 =  System.getProperty("user.dir") + File.separator + "asd" +  File.separator + "hiveTest-1.0-SNAPSHOT.jar";
        System.out.println(path);
        // 这里如果不加载两个测试类,会报一个类找不到的
        ClassTest classloader = new ClassTest(new URL[]{new URL("file:" + path),new URL("file:" + path1)});
//        ClassTest1 classloader = new ClassTest1(path);
        Class clazz = classloader.loadClass("com.tianzehao.A");
        Object a = clazz.newInstance();
        Method runMethod = clazz.getMethod("run");
        runMethod.invoke(a);
    }

}

你可能感兴趣的:(java classloader说明)