最近,我们重申了Java类加载和父母委托机制,并编写了一个SPI示例
我从网上找了照片,对着照片和课堂笔记整理了一下。
首先,java附带的类加载器分为三类: BootStrapClassLoader、ExtClassLoader和AppClassLoader。 它还支持用户指定的自定义类加载器
bootstrap class loader :在JVM中,c处理类加载的逻辑称为启动类加载器,由c编写,在java中为空,加载路径为JRE/lib/rt.jjava
加载Jre/lib/ext/*.jar的ExtClassLoader:扩展类加载器,如何查看:
publicstaticvoidmain (字符串[ ] args ) {
class loader class loader=class loader.getsystemclassloader ().getParent );
urlclassloaderurlclassloader=(URL classloader ) class loader;
URL [ ] URLs=URL class loader.geturls (; for(URLURL:URLS ) {
system.out.println(URL;
}
}
载入app class loader : APP应用程式类别载入器、载入使用者程式的类别载入器,以及CLASS_PATH指定的所有jar
publicstaticvoidmain (字符串[ ] args ) {
string [ ] URLs=system.getproperty (Java.class.path ).split ) : ); for(stringURL:URLS ) {
system.out.println(URL;
}
系统. out.println---------------------------------------------------- -。 ---------------------------------------------------------。
urlclassloaderclassloader=(URL class loader ) class loader.getsystemclassloader );
URL[] urls1=classLoader.getURLs (; for(URLURL:URLS1) {
system.out.println(URL;
}
}
父母委托机制:加载类时,AppClassLoader首先检查自己是否加载了当前class文件,如果加载了直接返回,如果未加载,则在自己的父类(ExtClassLoader )中加载ExtClassLoader也会首先检查自己是否已加载,如果已加载,则直接返回;如果未加载,则直接委托给要返回的BootStrapClassLoader。 如果尚未加载到BootStrapClassLoader,AppClassLoader将尝试加载。
打破父母委托方法:更改此加载过程,不委托给上面
packagecom.learn; importjava.net.URI; importjava.nio.file.Files; importjava.nio.file.Path; importjava.nio.file.Paths; publicclasscustomclassloaderextendsclassloader {
@ overridepublicclassloadclass (string name,boolean resolve ) throwsclassnotfoundexception { synchronized } getclassloadinglolor
classc=findloadedclass(name; if(c==null ) {long t0=System.nanoTime; try { if (name.starts with (com.learn ) ) /破坏父母的委托
c=查找类(name );
}else{
c=this.getParent ().loadclass ) ) name;
}
}catch(classnotfoundexceptione )//classnotfoundexceptionthrownifclassnotfound//from the non-nulllparentclassloader
}if(c==null ) ({//If still not found,theninvokefindclassinorder//to find the class )。
long t1=System.nanoTime (;
c=查找类(name ); //this is the defining class loader; 记录状态
sun.misc.perfcounter.getparentdelegationtime ().addtime ) T1-T0 );
sun.misc.perfcounter.getfindclasstime ().addelapsedtimefrom ) ) T1;
sun.misc.perfcounter.getfindclasses ().increment );
}
(if )求解) {
解决类(c;
}返回;
}
}
@ overrideprotectedclassfindclass (字符串名称) throwsclassnotfoundexception { return null;
}
}
SPI :服务发现的机制。 通过在ClassPath路径下的META-INF/services文件夹中搜索文件,自动加载文件中定义的类。 此机制允许许多框架扩展,例如Dubbo和JDBC都使用SPI机制
代码如下。
首先定义公共接口
packagecom.learn.spi.common; publicinterfaceijdbc { void connection (;
}
然后是两个实现类
packagecom.learn.spi.mysql; import com.learn.SPI.com mon.I JDBC; publicclassmysqljdbcimplementsijdbc {
@Overridepublic voidconnection () {
system.out.println (' thisismysqljdbc . ';
}
}
packagecom.learn.spi.oracle; import com.learn.SPI.com mon.I JDBC; publicclassoraclejdbcimplementsijdbc {
@Overridepublic voidconnection () {
system.out.println (' thisisoraclejdbc . ';
}
}
最后一个main函数使用服务加载器调用
packagecom.learn.spi.gateway; import com.learn.SPI.com mon.I JDBC; 导入Java.util.service loader; publicclassgatewaymain { publicstaticvoidmain { string [ ] args }
serviceloaderipays=服务加载器. load (I JDBC.class; for(IjdbcIjdbc:ipays ) {
iJdbc.connection (;
}
system.out.println('end . ';
}
}
META-INF/services文件夹下的文件名被定义为接口的完整路径名,文件内容是实现类的完整路径名,在此由JDK源代码进行了规定
com.learn.SPI.Oracle.Oracle JDBC
com.learn.spi.mysql.MysqlJdbc
执行结果: