问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

JAVA类加载机制之Classloader以及打破加载机制的方式

发布网友 发布时间:2024-09-27 01:32

我来回答

1个回答

热心网友 时间:2024-10-04 10:05

在jDK1.8中,Classloader加载class的字节码到JVM,它是遵循双亲委派模型的加载机制,主要是由BootstrapClassLoader,ExtClassLoader、AppClassloader,然后是自定义的Classloader加载,这样做主要是保证JDK的内部类加载安全性,所以优先加载JDK的ClassPath的jar包的类.双亲委派模型的如下图所示,其实就是由两级父Classloader加载,分别是BootstrapClassloader和ExtClassloader。

JDK的双亲委派模型

以下是Classloader的loadClass的和核心代码:

首先获取class的name的锁,是为了防止多线程并发的加载一个类,只有一个线程去加载,

findLoadedClass获取JVM已经加载的缓存中该Classloader实例是否已经加载该类, JVM底层实际是SystemDictionary,其底层是HASH表实现。

如果JVM的缓存没有加载过这个className,则先交给parent加载器加载,如果parent为空,则由BootstrapClassloader去加载,由于BootstrapClassloader是由C++实现,java没有这个类,所以通过JNI调用JVM的函数去加载。

果还没有加载到,则子类实现的findClass方法去加载。

最后判断resolve参数,是否处理class的链接。

最后返回class,没有加载到,由子类抛出ClassNotFoundException异常.

protectedClass<?>loadClass(Stringname,booleanresolve)throwsClassNotFoundException{synchronized(getClassLoadingLock(name)){//First,checkiftheclasshasalreadybeenloadedClass<?>c=findLoadedClass(name);if(c==null){longt0=System.nanoTime();try{if(parent!=null){c=parent.loadClass(name,false);}else{c=findBootstrapClassOrNull(name);}}catch(ClassNotFoundExceptione){//ClassNotFoundExceptionthrownifclassnotfound//fromthenon-nullparentclassloader}if(c==null){//Ifstillnotfound,theninvokefindClassinorder//tofindtheclass.longt1=System.nanoTime();c=findClass(name);//thisisthedefiningclassloader;recordthestatssun.misc.PerfCounter.getParentDelegationTime().addTime(t1-t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if(resolve){resolveClass(c);}returnc;}}JDK 打破双亲委派模型的两种方式继承ClassLoader,并重写loadClass

从JVM层的缓存查询当前Classloader是否加载过。

如果没有直接从本地资源查询是否有有对应的资源,如果有,则直接调用define进行加载到JVM,返回Class.

没有本地资源没有,则从parent的Classloader加载相应的资源.

最后返回Class.

@OverridepublicClass<?>loadClass(Stringname)throwsClassNotFoundException{System.out.println("loadClass:"+name);synchronized(getClassLoadingLock(name)){//First,checkiftheclasshasalreadybeenloadedClass<?>c=findLoadedClass(name);if(c!=null){returnc;}byte[]bt=classNameToContent.get(name);if(bt!=null){try{returndefineClass(name,bt,0,bt.length);}catch(Exceptione){e.printStackTrace();}}try{if(getParent()!=null){c=getParent().loadClass(name);}}catch(ClassNotFoundExceptione){//ClassNotFoundExceptionthrownifclassnotfound//fromthenon-nullparentclassloader}if(c!=null){returnc;}}returnnull;}使用Thread的contextClassLoader

JDK中利用线程的contextClassloader去打破双亲委派模型的例子就是Serviceloader, Serviceloader是JDK里面全称是Service Provider Interface,是实现服务提供接口,实现插件的方式,例如JDBC的Driver就是使用JDK的SPI,具体实现是适配不同的数据库,由于Driver是在rt.jar是由BootstrapClassloader加载,而接口实现类是由第三方的jar包提供,所有BootstrapClassLoader就没有办法就在,所以JDK做了一个妥协, 委派给当前线程的contextloader去加载实现类 下面是ServiceLoader的load方法,可以看出是获取当亲线程的contextClassloader去加载的接口的实现类。当前主线程类加载器默认是AppClassloader加载器加载。这样就是违反了双亲委派模型.

publicstatic<S>ServiceLoader<S>load(Class<S>service){ClassLoadercl=Thread.currentThread().getContextClassLoader();returnServiceLoader.load(service,cl);}并行类加载机制

前面介绍Classloader的抽象类中loadClass方法,加载开始时,需要获取类全名的锁, 如果用到了并行类加载机制,就会用到. 如果需要使用并行类加载机制,只有再自定义的类加载加一个静态代码块中,增加下面一行。

static{ClassLoader.registerAsParallelCapable();}

ClassLoader#registerAsParallelCapable

将自定义继承ClassLoader的类注册到ParallelLoaders的Set集合中.

protectedstaticbooleanregisterAsParallelCapable(){Class<?extendsClassLoader>callerClass=Reflection.getCallerClass().asSubclass(ClassLoader.class);returnParallelLoaders.register(callerClass);}

ParallelLoaders类中其实就是维护一个Classloader实现类的Set,其中元素都是调用registerAsParallelCapable注册为并行类加载的classloader,

privatestaticclassParallelLoaders{privateParallelLoaders(){}//thesetofparallelcapableloadertypesprivatestaticfinalSet<Class<?extendsClassLoader>>loaderTypes=Collections.newSetFromMap(newWeakHashMap<Class<?extendsClassLoader>,Boolean>());static{synchronized(loaderTypes){loaderTypes.add(ClassLoader.class);}}/***Registersthegivenclassloadertypeasparallelcapabale.*Returns{@codetrue}issuccessfullyregistered;{@codefalse}if*loader'ssuperclassisnotregistered.*/staticbooleanregister(Class<?extendsClassLoader>c){synchronized(loaderTypes){if(loaderTypes.contains(c.getSuperclass())){//registertheclassloaderasparallelcapable//ifandonlyifallofitssuperclassesare.//Note:givencurrentclassloadingsequence,if//theimmediatesuperclassisparallelcapable,//allthesuperclasseshigherupmustbetoo.loaderTypes.add(c);returntrue;}else{returnfalse;}}}/***Returns{@codetrue}ifthegivenclassloadertypeis*registeredasparallelcapable.*/staticbooleanisRegistered(Class<?extendsClassLoader>c){synchronized(loaderTypes){returnloaderTypes.contains(c);}}}

Classloaer构造函数中,

如果Classloader注册过并行类加载器,则创建parallelLockMap的锁的HashMap,

privateClassLoader(Voidunused,ClassLoaderparent){this.parent=parent;if(ParallelLoaders.isRegistered(this.getClass())){parallelLockMap=newConcurrentHashMap<>();package2certs=newConcurrentHashMap<>();domains=Collections.synchronizedSet(newHashSet<ProtectionDomain>());assertionLock=newObject();}else{//nofiner-grainedlock;lockontheclassloaderinstanceparallelLockMap=null;package2certs=newHashtable<>();domains=newHashSet<>();assertionLock=this;}}

Classloaer#getClassLoadingLock

在loadClass中获取类锁中,会判断parallelLockMap不为空,会创建一个Object对象作为这个classloader类的锁,然后放入hashMap中. 这样进行类加载过程,就synchonized锁就不是锁Classloader实例的this指针,而是Hashmap中获取加载类全名的锁,这样不同类全名就可以并行加载,这样减少了锁的粒度,提升类加载的速度.

protectedObjectgetClassLoadingLock(StringclassName){Objectlock=this;if(parallelLockMap!=null){ObjectnewLock=newObject();lock=parallelLockMap.putIfAbsent(className,newLock);if(lock==null){lock=newLock;}}returnlock;}

总结 \ 本文主要就JDK的阐述了双亲委派模型以及JDk中打破双亲委派的两种方式,最后介绍了JDK中实现并行类加载的实现原理.

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
时光公主高性价比氪金项目一览介绍_时光公主高性价比氪金项目一览是什么... 时光公主氪金买什么好介绍_时光公主氪金买什么好是什么 时光公主氪金买什么好 氪金钻石消费攻略 ch61u可以用gtx960显卡吗? 为什么路由器和机顶盒变成黄色网络连接不上 索尼WH-1000XM3耳机怎么通过蓝牙连接 索尼WH-1000XM3蓝牙连接手机教程... 葫芦岛市行政执法投诉办法第一章 总则 葫芦岛市价格调节基金管理办法第一章 总则 葫芦岛市政府信息公开暂行规定第一章 总则 葫芦岛市人民政府制发规范性文件规定第一章总则 科学教育活动 怎样采集树叶 民族区域自治地方是什么呢? 你知道的哪些书描述过“双性共体”观? 书单来了| 5本同性恋经典,揭开同性之爱的甜蜜与酸楚 电脑开机之后桌面上的内容都没有了? 更改用户名之后,电脑上的文件夹怎么全部没有了,怎么样才可以还原? 欧路词典怎样导入词典文件啊? 不锈钢与天然石用云石胶能不能贴上吗? 硫磺皂洗脸对脸有坏处么? 京东付款码怎么用 有什么可以塞住耳朵,让耳朵听不见声音 学习 营改增属于什么政策 买套二手房写什么进住对朕? 买二手房迁居对联 Win10开机出现无法自动修复你的电脑未正确启动的解决方法 电脑C盘用户名怎么改 常州遥光辰苑交通方便吗?应该怎么过去? 电脑如何更改用户名? 最强得分机器!杜兰特投篮大揭秘 NBA湖人詹姆斯 django分页怎么调到首页或尾页(2023年最新解答) 物业合同纠纷主要问题有哪些 物业纠纷调解的种类主要有哪些 物业无合同纠纷处理的问题有哪些? ...往国外寄信,求好心人帮我写信封。邮寄地址:新加坡国立医科大学。 徐州医科大学地址在哪里 谁有网剧盛势的百度云资源啊 跪求啊 盛势到底什么时候播出啊 有资源的 可以百度云给我嘛。。 为什么易建联说只要沃尔在场上,球队直接变成4打6啊 为什么易建联说自己在NBA可以无视对方的防守啊? 为什么于嘉说当奇才队和山猫队打不开局面的时候,只要易建联上场... 易建联去奇才有前途吗? 最起码拿个15+7的数据应该没问题吧? 11月11日火箭VS奇才 珍珠明目滴眼液的功效和作用 珍珠明目滴眼液 珍珠明目滴眼液的功效 caxa线切割怎样才能绘内齿轮 线切割YH-6电脑画齿轮画不出来是什么毛病? 795乘58竖式 用竖式计算85×8=79×5=86×7=36×9=37×6=55×5=96×4=88×3