复制代码

白话-双亲委派模型

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

posted @ 2020-06-10 15:24  pg633  阅读(175)  评论(0编辑  收藏  举报