为什么SPI要打破父母的委托机制
简要介绍ClassLoader的父母委托机制:
java类通过Classloader加载,Classloader之间存在继承关系,AppClassLoader继承ExtClassloader,继承BootstrapClassloader。 加载类后,子加载器将调用父加载器来加载类。 如果父加载器无法加载类,它将加载到子加载器中。 子加载器也在加载失败时报告异常。
可见父母委托机制是自下而上的上载方式,SPI如何打破这种关系?
例如,考虑JDBC加载驱动程序。
JDBC4.0或更高版本支持以SPI格式加载java.sql.Driver的实现类。 SPI的实现方式是通过service loader.load (驱动程序. class )的方法,分别实现驱动程序接口的lib的meta-INF/services/Java.SQL.dririver接口
驱动加载的过程大致在以上,但在哪里打破了父母的代理模式呢?
首先,让我们看看如果不加载Thread.currentThread ().getContextClassLoader () )加载器,整个过程将会怎么样。
从元-INF/services/Java.SQL.driver文件中获取实现类名DriverA
使用class.forname(「xx.xx.Drivera”)加载实现类
Class.forName ) )方法缺省情况下使用当前类的ClassLoader。 JDBC在驱动程序管理器类中调用驱动程序管理器。 当前类是驱动程序管理器,其加载器是bootstrap类加载器。
使用BootstrapClassLoader加载非rt.jar包中的xx.xx.DriverA类时,找不到该类
要加载xx.xx.DriverA,需要app类加载器或其他自定义类加载器
最终冲突是BootstrapClassLoader加载的类,它调用AppClassLoader加载实现类
在父加载器加载的类中,会出现如何调用子加载器来加载类的问题。
jdk有两种方法: thread.current thread (.getcontextclassloader )和class loader.getsystemclassloader )。 一般而言,jdk是AppClassLoader,getsystemclasssloader )
在SPI中,Thread.currentThread ().getContextClassLoader ) )用于加载实现类,并将其实现为核心包中的基类调用用户代码