java双亲委派机制

1.类的加载过程

当我们在使用某个对象时,jvm需要先将class文件加载进内存,大改款流程如下:

加载:将硬盘上的class文件读到内存生成一个Class对象,这一步通常是在使用到这个类时 才进行加载,属于懒加载

验证:校验class字节码文件是否符合java规范

准备:给静态变量分配内存,进行初始化,这里的初始化是指按照jvm的规范赋默认值,并不是类中定义的值

解析:将class文件的符号引用替换为直接引用,符号引用指的是我们在类中写的各种关键字,替换为内存地址,也就是静态链接

初始化:对静态变量赋值,执行静态代码块

类加载到方法区后,会创建一个Class对象放到堆区(heap)

2.类加载器和双亲委派机制

引导类加载器(BootstrapClassloader):负责加载jre下lib包下的核心类库,如rt.jar等

扩展类加载器(ExtClassloader):用于加载jre下lib/ext下的类库

应用类加载器(AppClassloader):用于加载我们自己的应用类

直接上代码:

java的两个类加载器都是Launcher.class的内部类,都继承URLClassLoader

在创建Launcher对象时,会初始化AppClassLoader对象,并且指定parent为ExtClassLoader

经过一系列的点点后到了这里,parent=ExtClassLoader

2.1 类加载器的源码

入口是执行AppClassLoader的loadclass方法,最终都会执行到其父类的loadclass方法

在这里首先会从AppClassLoader拿一次看有没有加载过,如果加载了就直接返回,如果没有则调用parent再次执行loadclass方法,父类也没有则调用findBootstrapClassorNull去获取。缓存中没有加载的话就再从父到子去加载。流程图也如下:

2.2 打破双亲委派机制

要打破双亲委派机制就要重写loadclass方法,可以模仿Tomcat的写法,重写findclass的逻辑,自己读取class文件然后传到defindClass方法,这样就完成了自定义类加载器

package com.test;

import java.io.FileInputStream;
import java.lang.reflect.Method;


public class MyClassLoader extends ClassLoader{

    private String classPath;

    public MyClassLoader(String classPath) {

        this.classPath = classPath;
    }

    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                   if(!name.startsWith("com.classload")){
                       c=getParent().loadClass(name);
                   }else {
                       c = findClass(name);
                   }
                    long t1 = System.nanoTime();

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
    protected Class<?> findClass(final String name) {
        byte[] b = new byte[0];
        try {
            b = loadByte(name);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return defineClass(name, b, 0, b.length);

    }
    private byte[] loadByte(String name) throws Exception {
        name = name.replaceAll("\\.", "/");
        FileInputStream fis = new FileInputStream(classPath + "/" + name
                + ".class");
        int len = fis.available();
        byte[] data = new byte[len];
        fis.read(data);
        fis.close();
        return data;

    }

    public static void main(String[] args) throws Exception {
        MyClassLoader myClassLoader = new MyClassLoader("/Users/ligang/Desktop/code/test");
        Class<?> aClass = myClassLoader.loadClass("com.classload.User");
        Object o = aClass.newInstance();
        Method print = aClass.getDeclaredMethod("print", null);
        print.setAccessible(true);
        print.invoke(o,null);
        System.out.println(aClass.getClassLoader().getClass().getName());
    }
}

执行结果:

Connected to the target VM, address: '127.0.0.1:50906', transport: 'socket'
加载成功
com.test.MyClassLoader
Disconnected from the target VM, address: '127.0.0.1:50906', transport: 'socket'

Process finished with exit code 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值