• 白话-双亲委派模型


    0 背景

    将技术简单叙述

    1 说明

       定义: 就是 java 虚拟机类加载机制 
      java 运行的是字节码 说的就是class, classloder 就是把class 变成内存对象的一个东西(这么理解  虽然不准确但是不要纠结)
     父 class 使用的是 父classloder 加载 
      
      破坏双亲委派模型 就是用父classloder 加载子类class,产品 jdbc
    

    2 看例子

    2.1 自定义classloder

    package classloder;
    
    /**
     * @author lianzheng04
     * @version 1.0
     * @date 2020/6/10 10:36 上午
     */
    
    import java.io.*;
    
    /**
     * Created by zejian on 2017/6/21.
     * Blog : http://blog.csdn.net/javazejian [原文地址,请尊重原创]
     */
    public class FileClassLoader extends ClassLoader {
        private String rootDir;
    
        public FileClassLoader(String rootDir) {
            this.rootDir = rootDir;
        }
    
        /**
         * 编写findClass方法的逻辑
         *
         * @param name
         * @return
         * @throws ClassNotFoundException
         */
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            // 获取类的class文件字节数组
            byte[] classData = getClassData(name);
            if (classData == null) {
                throw new ClassNotFoundException();
            } else {
                //直接生成class对象
                return defineClass(name, classData, 0, classData.length);
            }
        }
    
        /**
         * 编写获取class文件并转换为字节码流的逻辑
         *
         * @param className
         * @return
         */
        private byte[] getClassData(String className) {
            // 读取类文件的字节
            String path = classNameToPath(className);
            try {
                InputStream ins = new FileInputStream(path);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int bufferSize = 4096;
                byte[] buffer = new byte[bufferSize];
                int bytesNumRead = 0;
                // 读取类文件的字节码
                while ((bytesNumRead = ins.read(buffer)) != -1) {
                    baos.write(buffer, 0, bytesNumRead);
                }
                return baos.toByteArray();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 类文件的完全路径
         *
         * @param className
         * @return
         */
        private String classNameToPath(String className) {
            return rootDir + File.separatorChar
                    + className.replace('.', File.separatorChar) + ".class";
        }
       public static void  func1(){
           String rootDir = "/Users/lianzheng/icu/jql/sl-spring/src/main/java";
           //创建自定义文件类加载器
           FileClassLoader loader = new FileClassLoader(rootDir);
    
           try {
               //加载指定的class文件
               Class<?> object1 = loader.loadClass("classloder.DemoObj");
               System.out.println(object1.newInstance().toString());
    
               //输出结果:I am DemoObj
           } catch (Exception e) {
               e.printStackTrace();
           }
        } 
    
        // 热部署
        public static void main(String[] args) throws ClassNotFoundException {
    //        String rootDir = "/Users/lianzheng/icu/jql/sl-spring/src/main/java";
            // 使用findclass 时候需要进行类编译成class 文件
            String rootDir = "/Users/lianzheng/icu/jql/sl-spring/target/classes";
            //创建自定义文件类加载器
            FileClassLoader loader = new FileClassLoader(rootDir);
            FileClassLoader loader2 = new FileClassLoader(rootDir);
    
            try {
                //加载指定的class文件,调用loadClass()
    //            Class<?> object1 = loader.loadClass("classloder.DemoObj");
    //            Class<?> object2 = loader2.loadClass("classloder.DemoObj");
    //
    //            System.out.println("loadClass->obj1:" + object1.hashCode());
    //            System.out.println("loadClass->obj2:" + object2.hashCode());
    
                //加载指定的class文件,直接调用findClass(),绕过检测机制,创建不同class对象。
                Class<?> object3 = loader.findClass("classloder.DemoObj");
                Class<?> object4 = loader2.findClass("classloder.DemoObj");
    
                System.out.println("loadClass->obj3:" + object3.hashCode());
                System.out.println("loadClass->obj4:" + object4.hashCode());
    
                /**
                 * 输出结果:
                 * loadClass->obj1:644117698
                 loadClass->obj2:644117698
                 findClass->obj3:723074861
                 findClass->obj4:895328852
                 */
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    2.2 破坏双亲委派机制

    DriverManager.calss 
     static {
            loadInitialDrivers();
            println("JDBC DriverManager initialized");
     }
    // 这个部分加载了driver ,进入函数 loadInitialDrivers
    
    • 加载了一个接口 ->interface 实现是厂商的实现类
    • 进入 load 函数

      此时 相当于 使用 当前线程的 ContextClassLoader

    所以相当于 使用现在 父的classloder加载了子类的class

    不摸着石头过河,难道要在温柔乡睡到天昏地暗。

  • 相关阅读:
    跨境电商ERP中的自动化 5.平台订单自动打印面单
    小特工具箱新增功能:文档转换、代码转换和AI写诗词
    跨境电商ERP中的自动化 4.平台订单自动取运单号
    C#.NET 使用HttpWebRequest发送JSON
    .net core .net5 asp.net core mvc 与quartz.net 3.3.3 新版本调用方式
    .NET CORE .NET5 控制台程序使用EF连接MYSQL
    C#.NET 国密SM3withSM2签名与验签 和JAVA互通
    JAVA RSA 私钥签名 公钥验证签名 公钥验签
    java 读取控制台输入
    C#.NET RSA 私钥签名 公钥验证签名
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13309218.html
Copyright © 2020-2023  润新知