为了账号安全,请及时绑定邮箱和手机立即绑定

classloader总结

标签:
Java
classloader是什么

      我的理解classloader就是加载我们的类到内存的类,他主要就是寻找资源,即找到在他能搜索到的路径中,有没有我们的类。有的话就加载到内存。

系统的classloader

系统的classloader有三种

Bootstrap ClassLoader     负责加载java基础类,主要是 %JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等

Extension ClassLoader      负责加载java扩展类,主要是 %JRE_HOME/lib/ext 目录下的jar和class

App ClassLoader           负责加载当前java应用的classpath中的所有类。

双亲委托机制

    系统的classloader实行的是双亲委托机制,双亲委托机制就是在加载类的时候先去父类(此处的父类不是继承里面的父类,双亲委托机制是组合)里查找,如果父类加载到了就算子类的可以在自己的路径下找到,也不能加载。只会从父类中取到加到后的class。这样的好处就是不会重复加载类。

    此处只是说系统的classloader,因为你自己写的classloader不一定要遵循这个机制,而且有些情况必须不能遵循,例如tomcat等服务器,加载的时候不会遵循双亲委托(他的classloder是自己实现的),他是优先自己加载,自己加载不到才会委托父类加载,他是必须允许,相同的类会被重复加载。因为你两个web应用用到了相同的类,加载的时候是加载了一个web应用的类,那么解部署的时候必须不能删除该类,因为另一个web应用还在用。

自己写classloader

    知道这么多机制,肯定是为了自己写classloader,自己写的classloder有很多用处,例如自己做点字节码增加功能(当然javaagent也能做),做对类的加密解密功能等等。

    java提供了一个类帮助我们实现classloader,这个类是URLClassLoader,我们只需要继承这个类,覆写loadClass方法就可以,他必须调用父类的构造方法,传递url数组,这里的url数组里面就是这个classloader能寻找的路径。如果在你的路径中寻找,这是你需要实现的逻辑,大部分还是直接调用父类的方法,因为他已经知道路径了,很多时候你不需要去处理,java已经帮你实现了。

public class Loader extends URLClassLoader {

    public Loader(URL[] urls) {
        super(urls);
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return super.loadClass(name);
    }

}

这就是一个遵循双亲委托机制的classloader。很简单。

    如何破坏双亲委托呢?这个大家已经明了了。就是改loadClass方法里加载的过程。举个例子,如果你先写个自己查找的方法放在super.loadClass(name)之前,那么已经不是默认的双亲机制了。这里必须介绍一个方法,就是加载类到内存的方法defineclass。具体再怎么加载,这个就不需要我们管了。因为确实用不到那么多。

如何使用classloader

Thread.currentThread().setContextClassLoader(loader);

    通过设置当前线程classloader来更改classloader,这种方法最常用,这样就简单的更改了classloader,以后这个线程加载类就靠你设置的classloader,不再直接是appclassloader。

    第二种用法用来测试classloader不错,就是直接调用你自己写的classloder的loadclass方法获取Class对象。

自己写的classloader是谁来加载?

    这个不用想了,是app classloader,虽然你是classloader,但是对jvm而言,他只是个字节码文件罢了。他在app classloader的加载路径上。

类A非类A

    由于classloader会出现一个很有意思的问题,类似古代白马非马的问题。举个例子当一个类被两个classloader加载时,第一个classloader产生类A对象,传递给另一个classloderA的声明,结果就出现转换出错的问题。

    在java里,只有被同一个classloader加载的类才会被认为是同一个类,两个classloader都加载了类A,那么就会被认为是两个完全不相干的类。(但是两个类A都继承B,用B对象的引用去接收赋值没问题,只是两个相同的类赋值这个类的声明才会有这个问题)。

 总结

    classloader的重点是你加载类的路径和文件,如果保证了路径和文件,那么classloader也就没啥了,因为剩下的完全依靠父类方法就可以,除非你的处理需要修改其他方法。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消