Java中如何破坏双亲委派模型

破坏双亲委派模型

文中的双亲委派模型并不是一个强制性的约束模型,而是Java设计者推荐给开发者的类加载器实现方式。在Java的世界中大部分的类加载器都遵循这个模型,但是也有例外,目前为止,双亲委派模型主要出现过三次较大规模的“被破坏”情况。

  1. 第一次:在双亲委派模型发布之前,即JDK1.2之前。为了兼容之前JDK版本中自定义类加载器的实现。(即没有按照双亲委派模型来设计)

    解决办法:把自己的类加载器逻辑写到findClass()方法中,在loadClass()方法的逻辑里如果父类加载失败,则会调用自己写的findClass()方法来完成加载,这样就可以保证新写出来的类加载器是符合双亲委派模型的。

  2. 第二次:自身的缺陷所致。

    JNDI服务需要调用独立厂商实现并部署在应用程序的ClassPath下的JNDI接口提供者(SPI)的代码,但是启动类加载器不认识这些代码。

    解决办法:引入上下文类加载器(Thread Context ClassLoader)。这个类加载器可以通过java.lang.Thread类的**setContextClassLoaser()**方法进行设置,如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围都没有设置过的话,那这个类加载器默认就是应用程序的类加载了。

    类似的服务还有:JDBC、JCE、JAXB、JBI等等。

  3. 第三次:用户对动态性的追求而导致的,例如:代码热替换、热部署

    解决办法:OSGI实现模块化热部署的关键是它自定义的类加载机制实现的。OSGi每个模块都有自己独立的classpath。如何实现这一点呢?是因为OSGi采取了不同的类加载机制:

    1、OSGi为每个bundle提供一个类加载器,该加载器能够看到bundle Jar文件内部的类和资源;
    2、为了让bundle能互相协作,可以基于依赖关系,从一个bundle类加载器委托到另一个bundle类加载器。
    3、当需要更换一个Bundle时,就把Bundle连同类加载器一起换掉以实现代码的热部署。

双亲委派模型破坏举例(淘宝面试题)

原生的JDBC中Driver驱动本身只是一个接口,并没有具体的实现,具体的实现是由不同数据库类型去实现的。例如,MySQL的mysql-connector-.jar中的Driver类具体实现的。 原生的JDBC中的类是放在rt.jar包的,是由启动类加载器进行类加载的,在JDBC中的Driver类中需要动态去加载不同数据库类型的Driver类,而mysql-connector-.jar中的Driver类是用户自己写的代码,那启动类加载器肯定是不能进行加载的,既然是自己编写的代码,那就需要由应用程序启动类去进行类加载。于是乎,这个时候就引入线程上下文件类加载器(Thread Context ClassLoader)。有了这个东西之后,程序就可以把原本需要由启动类加载器进行加载的类,由应用程序类加载器去进行加载了。

需要保留双亲委派模型:extends ClassLoader,重写 findClass()
破坏双亲委派模型:直接重写 loadClass()

参考资料
https://blog.csdn.net/luoyang_java/article/details/92598142
https://www.cnblogs.com/barrywxx/p/8522216.html

你可能感兴趣的:(JVM)