zoukankan      html  css  js  c++  java
  • 《Java 底层原理》Java 类加载器

    前言

    工作中需要实现一种功能:动态加载类对象信息,简单说就是class变了Jvm能够立马知道并且加载到内存。

    类加载器分类

    Java类加载器分为两种,一种是加载启动类,另一种是其他类加载器。Java加载类的关系:Launcher

    1. 启动类加载器(BootstrapClassLoader)。

    Java 程序是运行在Jvm上,所以Jvm需要知道Java程序的入口在何处(启动类)。Jvm通过c++的LoadMainClass去加载Java程序的sun.launcher.LauncherHelper。并且通过他加载Mian函数所在的扩展类ClassLOader和AppClassLoader。

    2. Java自己编写的类加载器。

    2.1 ExtClassLoader 扩展类加载器

    ExtClassLoader类是没有父类的。

    String var0 = System.getProperty("java.ext.dirs");

    因为上面的代码,所以可以设置类扩展类加载器加载Jar包的目录。

    2.2 AppClassLoader Class_path 指定的Jar包

    AppClassLoader的父类为ExtClassLoader。我们main函数所在类的类加载器是AppClassLoader。

    Java类加载器会加载的Jar包路径

    import sun.misc.Launcher;
    
    import java.net.URL;
    
    public class ClassLoaderDemo1 {
        public static void main(String[] args) {
            String[] split = System.getProperty("sun.boot.class.path").split(";");
            for (int i = 0; i < split.length; i++) {
                System.out.println(split[i]);
            }
            System.out.println("========================================");
            URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
            for (int i = 0; i < urLs.length; i++) {
                System.out.println(urLs[i]);
            }
        }
    }

    运行结果:

    委派机制

    根据类加载器,画一个Java委派和加载的原理图。

    Java不会被重新加载是通过类的全限定名来判断的

    Java委派机制的好处。

    1. 保证核心包加载不受干扰。

    2.  保证class 加载唯一。

    SPI机制

    先看个案例

    public interface ServerSPI {
        void execMethod();
    }

    两个实现类

    public class ServerSPIImpl1 implements ServerSPI{
        @Override
        public void execMethod() {
            System.out.println("ServerSPIImpl1.execMethod 执行");
        }
    }

    public class ServerSPIImpl2 implements ServerSPI {
        @Override
        public void execMethod() {
            System.out.println("ServerSPIImpl2.execMethod 执行");
        }
    }

    配置(目录要一致,文件名是接口名)

    文件内容(类的全限定名)

    写一个测试类

    import sun.misc.Service;
    import java.util.Iterator;
    
    public class SpiTest {
        public static void main(String[] args) {
            Iterator<ServerSPI> providers = Service.providers(ServerSPI.class);
    
            while(providers.hasNext()) {
                ServerSPI ser = providers.next();
                ser.execMethod();
            }
        }
    }

    运行结果:

    ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);   -- 这个方式也可以获取加载的对象。

    该案例没有使用Java的委派机制实现了类的加载功能。

    Service 的源码重点:

    private static final String prefix = "META-INF/services/";    -- 为什么目录是指定的。
        public static <S> Iterator<S> providers(Class<S> var0) throws ServiceConfigurationError {
            ClassLoader var1 = Thread.currentThread().getContextClassLoader();     -- 获取线程所在个类ClassLoader。
            return providers(var0, var1);
        }

    SPI加载类的原理:

    1. 需要指定目录,程序需要在知道目录下找到接口信息,根据接口找到实现类。

    2. 通过线程所在的ClassLoader 加载实现,通过反射实例化对象。

    3. 其他细节源码,有兴趣自己了解。

    4. 我们经常使用的JDBC就是使用SPI机制实现类加载。

    自定义类加载器

    实现热部署功能案例:https://www.cnblogs.com/jssj/p/13251804.html

    案例中很好的运用了自定义类加载器,并且实现了如何打破Java委派机制。

    总结

    类加载器的种类,类加载器的各自分工,类加载的委派过程,SPI机制,自定义加载器的实现。

  • 相关阅读:
    保持URL不变和数字验证
    centOS ftp key?
    本地环境测试二级域名
    linux 解决You don't have permission to access 问题
    php smarty section loop
    php header Cannot modify header information headers already sent by ... 解决办法
    linux部分命令
    Linux 里面的文件操作权限说明
    用IT网络和安全专业人士视角来裁剪云的定义
    SQL Server 2008 R2炫酷报表"智"作有方
  • 原文地址:https://www.cnblogs.com/jssj/p/14285530.html
Copyright © 2011-2022 走看看