首页   快速返回

java类加载器要点整理     所属分类 java
启动类加载器  BootstrapClassLoader
扩展类加载器  ExtClassLoader
应用类加载器  AppClassLoader
自定义加载器

JAVA_HOME/lib 
lib/ext
classpath

加载路径
System.out.println("boot:"+System.getProperty("sun.boot.class.path"));
System.out.println("ext:"+System.getProperty("java.ext.dirs"));
System.out.println("app:"+System.getProperty("java.class.path"));

//加载器之间的层级关系
 public class ClassLoaderTest { 

    public static void main(String[] args) { 
        ClassLoader loader = ClassLoaderTest.class.getClassLoader(); 
        while (loader != null) { 
            System.out.println(loader.toString()); 
            loader = loader.getParent(); 
        } 
    } 
 }

// 没有显示引导类加载器,获取引导类加载器时,返回null。
sun.misc.Launcher$AppClassLoader@xxx
sun.misc.Launcher$ExtClassLoader@xxx



双亲委派模型


自定义类加载器且不破坏双亲委派模型,继承ClassLoader类并重写findClass方法。
自定义类加载器且破坏双亲委派模型,继承ClassLoader类并重写findClass方法 和 loadClass方法。


ClassLoader.getSystemClassLoader()  获取应用加载器


自定义类加载器继承ClassLoader,一般是继承URLClassLoader


public class MyClassLoader extends ClassLoader { 

    protected Class findClass(String name) throws ClassNotFoundException { 
        byte[] bytes = readClassBytes(name); 
        if (bytes == null) { 
            throw new ClassNotFoundException(); 
        }else{ 
            return defineClass(name, bytes, 0, bytes.length); 
        } 
    } 


URL url1 = new URL("file:///Users/dugang/my/classes/");
URL url2 = new URL("file:///Users/dugang/my/lib/xxx.jar");

URLClassLoader ucl = new URLClassLoader(new URL[]{url1,url2});
		
		
		
Class cls = ucl.loadClass("dyyx.my.Cat");
Class cls2 = Class.forName("dyyx.my.Cat",true,ucl);




上下文类加载器  父类加载器使用子类加载器 加载类
SPI  jdbc

//建立数据库连接各个不同参数的方法最终都会走到这里
private static Connection getConnection(
        String url, java.util.Properties info, Class caller) throws SQLException {
        //获取调用者的类加载器
        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
        synchronized(DriverManager.class) {
            //如果为null,则使用上下文类加载器
            //这里是重点,什么时候类加载器才会为null? 当然就是由根类加载器加载的类了
            if (callerCL == null) {
                callerCL = Thread.currentThread().getContextClassLoader();
            }
        }

        //...

        for(DriverInfo aDriver : registeredDrivers) {
            //使用上下文类加载器去加载驱动
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    //如果加载成功,则进行连接
                    Connection con = aDriver.driver.connect(url, info);
                    //...
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }
            } 
            //...
        }
    }
    
 

类隔离 热部署 热替换 
tomcat 类加载机制
jsp热部署


    
    
类加载常见错误


ClassNotFoundException
ClassNotFoundError
NoClassDefFoundError
ClassCastException


java.lang.LinkageError: loader (instance of  dyyx/my/MyClassLoader): attempted  duplicate class definition for name: "dyyx/my/Cat"

重复加载相同的类会报错 ,因此热部署时,需要把classload一起替换掉


-XX:+TraceClassLoading 
-XX:+TraceClassUnloading 



类名错误
jar包没有引入
jar 包冲突



测试代码


ClassLoadTest.java package dyyx.my; public class ClassLoadTest extends ClassLoader { public static void main(String[] args) throws Exception { ClassLoader loader = ClassLoadTest.class.getClassLoader(); while (loader != null) { System.out.println(loader.toString()); loader = loader.getParent(); } System.out.println("boot:"+System.getProperty("sun.boot.class.path")); System.out.println("ext:"+System.getProperty("java.ext.dirs")); System.out.println("app:"+System.getProperty("java.class.path")); System.out.println(ClassLoader.getSystemClassLoader()); System.out.println(System.getProperty("java.system.class.loader")); // -XX:+TraceClassLoading // [Loaded dyyx.my.ClassLoadTest from file:/Users/dugang/fun/hellocode/bin/] try{ Class.forName("x.y.z.A"); }catch(Throwable e){ // java.lang.ClassNotFoundException: x.y.z.A System.out.println(e); } String className = "dyyx.my.Hello"; Class cls = ClassLoader.getSystemClassLoader().loadClass(className); // 类不会初始化 // class1=class dyyx.my.Hello System.out.println("class1="+cls); try{ // 类初始化异常 cls = Class.forName(className); System.out.println("class2="+cls); }catch(Throwable e){ // java.lang.ExceptionInInitializerError System.out.println(e); } try{ Hello.hello(); }catch(Throwable e){ // java.lang.NoClassDefFoundError: Could not initialize class dyyx.my.Hello System.out.println(e); } } }
Hello.java package dyyx.my; import java.util.Date; public class Hello { static{ boolean flag = true; if(flag){ throw new RuntimeException("hello static init error"); } } public static void hello(){ System.out.println("hello,"+new Date()); } }

上一篇     下一篇
JMX配置及java客户端远程连接JMX端口

AQS要点整理

自定义类加载器例子

kibana安装配置及使用

elasticsearch7.0压测问题记录

elasticsearch工具