关于java类加载器的试验和理解

目录

1、如何用自己实现的的类加载器加载自己的类

2、是否可以重复加载同一个类

3、关于SPI和java热替换


==========================================分割线=========================================================


1、实现一个类加载器,并加载一个类

要加载的类Object 

public class Object {
}


类加载器MyClassLoader: 

public class MyClassLoader extends ClassLoader {
    /**
     * Finds the class with the specified <a href="#name">binary name</a>.
     * This method should be overridden by class loader implementations that
     * follow the delegation model for loading classes, and will be invoked by
     * the {@link #loadClass <tt>loadClass</tt>} method after checking the
     * parent class loader for the requested class.  The default implementation
     * throws a <tt>ClassNotFoundException</tt>.  </p>
     *
     * @param name The <a href="#name">binary name</a> of the class
     * @return The resulting <tt>Class</tt> Object
     * @throws ClassNotFoundException If the class could not be found
     * @since 1.2
     */
    @Override
    protected Class<?> findClass(String  name) throws ClassNotFoundException {
        System.out.println(1);
        try {
            FileInputStream i = new FileInputStream(new File("/Document/Object.class"));
            byte b[] = new byte[i.available()];
            i.read(b);
            i.close();
            return defineClass(name, b, 0, b.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}


main函数: 

public class ClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        MyClassLoader myClassLoader = new MyClassLoader();
        myClassLoader.loadClass("Object");
        System.out.println(myClassLoader.loadClass("Object").getClassLoader());
    }
}


全部放到Documents目录下运行:


输入结果展示Object的类加载器为AppClassLoader


分析:

由于我们并没有重写loadClass方法,所有还是双亲委派模型,会去寻找默认的父加载器,即AppClassLoader,因为Object所在的位置为javaclasspath,正好符合AppClassLoader的加载规则,则进行加载。需要让Object类不符合AppClassLoader的加载条件。(查看javaclasspath,可以通过“System.out.println(System.getProperty(“java.class.path”));”获取。)


改进:

Object类放到桌面目录,更改MyClassLoader去桌面加载Object类,其他不动: 

FileInputStream i = new FileInputStream(new File("/Desktop/Object.class"));


运行结果: 


输入结果显示Object的类加载器为MyClassLoader,完成。




2、用自己的类加载器重复加载一个类


main函数更改如下:  

public class ClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        MyClassLoader myClassLoader = new MyClassLoader();
        myClassLoader.findClass("Object");
        myClassLoader.findClass("Object");
    }
}

运行结果: 


分析:

直接调用两次findClass方法(findClass会直接加载Class,自己在classLoader重写的方法),来模拟加载两次的情况。

加载两次会抛出异常,注意不要认为调用两次loadClass没错误,认为jvm允许重复加载类,因为loadClass内部有判断是否已经加载。




3SPIjava热替换


SPIjava定义的接口由最顶层类加载器加载,但是由于实现类一般为第三发实现,所以在引用后,由低于顶层类加载器的类加载,这个时候顶层类加载器无法找到该实现类。

为了解决这个问题,引入了线程上下文类加载器。在通过接口调用实现类方法时,通过该加载器加载类,并调用。

该类加载器,每个线程都是独立的,并且默认为AppClassLoader


热替换在了解后,发现并不是真正的替换原来在jvm永久区使用的Class类,而是用一个新的类加载器加载改动后的该类。然后在以后的使用中,使用这个新生成的Class类。

由于不断的Class类生成,必定会有老旧无用的Class类占永久区的内存空间,不过当该类的实例都被回收,且类没有使用,该类加载器也被回收后,fullGC就会回收Class类。

常见热替换为jsp,每个jsp页面对应一个类加载器,当定时发现jsp有变动后,就新建类加载器加载jsp








自己理解的,如有错误,欢迎指出。谢谢。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值