时间:2022-11-10 04:25:01
前面的步骤中描述的类加载器包括引导类加载器、扩展类加载器、APP应用程序类加载器和自定义加载器。
他们是怎么加载的呢? 其中,类加载具有父母委托机制。 加载类时,首先要求父加载器查找目标类,如果找不到,则要求更高一级的父加载器进行加载。 如果所有父加载器在自己的加载类路径下找不到目标类,请在自己的类加载路径中搜索并加载目标类。
如何加载此类加载器的类。 里面实现了父母委托机制
protectedclassloadclass (字符串名称, 布尔解析) throwsclassnotfoundexception ( synchronized ) getclassloadinglock ) naan ced checkiftheclasshasalreadybenloady if(c==null ) { long t0=System.nanoTime ); try { //判断当前类加载器的父加载器是否为空,如果不为空,则请求父类加载if ( parent!=null ) {c=parent.loadclass(name,false ); } else { //如果当前加载程序的父加载程序为空,则请求引导类加载程序加载该类c=findbootstrapclassornull ( name )。 }catch(classnotfoundexceptione )/classnotfoundexceptionthrownifclassnotfound//from the non-nullparentclassloader {//} theninvokefindclassinorder//to find the class.long t1=system.nano time (; 调用URLClassLoader的findClass方法在加载器的类路径中查找并加载该类c=findclass(name )。 //this is the defining class loader; recordthestatssun.misc.perfcounter.getparentdelegationtime ( ).addtime ) T1-T0 ); sun.misc.perfcounter.getfindclasstime ( ).addelapsedtimefrom ) T1; sun.misc.perfcounter.getfindclasses ( ).increment ); }if(resolve ) ) resolveclass ) c; } return c; }为什么要设计父母的委托机制? 沙箱安全机制:不加载自己编写的java.lang.String.class类。 由此,可以防止核心API库被随意篡改导致类的重复加载。 如果父亲已经加载了该类,则子ClassLoader不需要再次加载,确保加载类唯一性的全面责任机制是ClassLoader
父母任命java有spi技术
SPI的全称是Service Provider Interface,主要应用于供应商定制组件或插件。 java.util.ServiceLoader文档中有详细介绍。 简单总结一下java SPI机制的思想,在我们的系统中抽象出的每个模块都有很多不同的实现方案,包括日志模块、xml分析模块、jdbc模块等。 的面向对象设计中,一般推荐模块间基于接口的编程,模块间不硬编码实现类。 如果代码包含具体的实现类,则违反可插件原则,如果需要替换单个实现,则必须修改代码。 为了在模块组装时不在程序内动态地特定,服务发现机制是必要的。 Java SPI是指提供一种查找接口的服务实现的机制。 与IOC的思想相似,是将组装的控制权转移到程序之外。 在模块设计中,这个机制特别重要。 SPI的具体约定Java SPI的具体约定是,在服务提供商提供服务接口实现后,同时在jar包的META-INF/services/目录中创建以服务接口名称命名的文件。 该文件包含实现服务接口的具体实现类。 当外接程序组装此模块时,可以从jar包META-INF/services/中的配置文件中找到具体的实现类名,然后装载实例化并完成模块的注入。 基于这些约定,您可以很好地找到服务接口的实现类,而无需在代码中编写它们。 用于jdk提供服务和实现搜索的工具类。 java.util.ServiceLoader。
例如,我决定了一个接口,两个实现类,
publicinterfacedemo1{ string test ( string name ); } publicclassdemospi1implements demo1{ @ overridepublicstringtest ( string name ) system.out.println ( com.example.exament ) 返回空值; } publicclassdemospi1implements demo1{ @ overridepublicstringtest ( string name ) system.out.println ) com.example return nn }按照约定在META-INF/services/中新建文件名com.example.spi.test.Demo1的内容是
如何使用com.example.SPI.test.demos pi1com.example.SPI.test.demos pi 2?
publicstaticvoidmain ( string [ ] args ) serviceloaderload=service loader.load ( demo1. class ); Iterator iterator=load.iterator (; while(iterator.Hasnext ( ) ) { Demo1 next=iterator.next ); next.test('q ); }输出:在com.example.SPI.test.demos pi1com.example.SPI.test.demos pi 2中,SPI会做什么? 为什么SPI打破了父母的任命呢? 上面的iterator.next ) )下调用了此方法。 在此处,方法中调用了class.forname(cn、false、loader )。 我们需要在这里找出loader是从哪里进来的。
private S nextService ( ) . …classc=null; try{c=class.forname(cn,false,loader ); }catch(classnotfoundexceptionx ) fail ) service,' Provider ' cn ' not found ' ); ()请看这一行的代码
publicstaticserviceloaderload ( class service ) class loader cl=thread.current thread ).getContextClassLoader; returnserviceloader.load ( service,cl ); }Thread.currentThread ( ).getContextClassLoader ); 用这种方法获取的是上面的loader,这是BootrapLoader、ExtClassLoader还是AppClassLoader? 首先可以排除的是不行BootrapLoader。 ServiceLoader是BootrapLoader加载的,在构建Launcher时放入了AppClassLoader,所以请确保上面的内容是AppClassLoader。
publiclauncher((.try ) this.loader=launcher.app class loader.getappclassloader ) ) var1; }catch(ioexceptionvar9) throw new internal error ( ' couldnotcreateapplicationclassloader ',var9); } Thread.currentThread ( ).setcontextclassloader ( this.loader ); }这里是打破父母的委托,由AppClassLoader直接加载的。
总结JDK提供了一种方便的方法,可以定制和加载各种模块。 如果类名位于/META-INF中,则启动时将扫描所有jar包中符合约定的类名,然后调用forName ( )进行加载,但我的ClassLoader无法加载。 必须使用AppClassLoader进行加载