破坏双亲委派模型

第一次破坏,兼容JDK1.2之前的代码

双亲委派模型是在JDK1.2出现的,为了兼容已有代码,但类加载器的概念和抽象类

java.lang.ClassLoader则在Java的第一个版本就存在,面对已经存在用户自定义

类加载器的代码,无法以技术手段避免loadClass()被子类覆盖的可能性,只能在

java.lang.ClassLoader中添加一个新的protected方法findClass(),并引导

用户编写的类加载逻辑时尽可能重写这个方法,而不是在loadClass()中编写代码。

第二次破坏,自身缺陷导致的

双亲委派很好地解决了各个类加载器协作是基础类型的一致性问题(越基础的类由越上层

的加载器进行加载),基础类型之所以被称为“基础”,是因为它们总是作为被继承、调用的

API存在,但如果有基础类型又要调用回用户的代码情况呢?

典型的例子便是JNDI服务,JNDI存在的目的就是对资源进行查找和集中管理,

需要调用其他厂商实现并部署在应用程序的ClassPath下的JNDI服务提供者

接口(Service Provider InterfaceSPI)的代码,问题是启动类加载器绝不可能认识、加载这些代码。

为了解决这个困境,Java的设计团队引入了一个不大优雅的设计:线程上下文加载器(Thread Context ClassLoader)。

这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果创建线程时未设置,

将会从父线程中继承一个,默认是应用程序类加载器。

JNDI服务使用这个线程上下文加载器去加载所需要的SPI服务代码,这是一种父类加载器去请求子类加载器完成类加载

的行为。已经违背了双亲委派模型的一般性原则,但也是无可奈何的事。Java中涉及SPI的加载基本上都采用这种方式

完成,例如JNDIJDBCJCEJAXB、和JBI等。

SPI的服务提供者多于一个的时候,代码就只能根据具体提供者的类型来硬编码判断,

为了消除这种极不优雅的实现方式,在JDK6时,JDK提供了java.util.ServiceLoader类,

META-INF/services中的配置信息,辅以责任链模式,才算给SPI的加载提供了一种相对合理的解决方案。

第三次破坏,追求程序动态性

Java模块化,需要到JDK9