类加载器,是java安全的一部分,通常情况下我们是不用关心类的加载过程的,但这是通常情况下,非通常的情况下,我们要关心类的加载过程。并且要适度的控制类的加载过程。下面就结合我在开发过程中遇到的一个问题,讨论一下类加载器的相关知识。
在core java中,类加载器归类为安全的第一道门槛。因为java天生的类加载机制,避免了类的重复加载。保证了同一个类只被加载一次的这个要求。
介绍加载机制前,我们先来说一下几个名词(一家之言,具体定义请google一下)。
类加载器:将类加载进jvm中的一个工具。类的来源可以是网络、本地文件,数据库。(看一下URLclassLoader就可以知道,其实只要有一个完整的流,就可以根据该流将类加载至虚拟机)
双亲委托:是指在标准情况下,类加载器在需要加载一个类时,会先委托他的双亲加载器进行加载。如果双亲能加载到对应的类,则使用双亲的加载的类,如果双亲不能加载,再自己进行加载。
BootstrapClassLoader:引导类加载器,是加载虚拟机核心库的加载器。
ExtClassLoader:用来加载jre/lib/ext目录下的jar包。
AppClassLoader:加载设置的classpath路径下的jar包。
URLclassLoader:j2SE包含的一个类加载器,在项目中自定义类加载器,集成该类加载器通常是最佳的选择。
介绍完了名词:下面我就结合我的实际经验,简单介绍一下我遇到的问题。
事情是酱紫的。一个软件供应商为两个用户提供了不同版本的软件,而我方的软件需要在同一个应用中同事连接到这两个用户在连接到用户的过程中,需要使用用户对应的jar包。这就导致了在同一个应用中,需要以来不同版本的一个jar包,并且jar包中大部分内容是相同的(有许多相同名称和内容的类)。
问题出现了,这是一个类加载器解决的典型问题。
我最初解决这个问题的方案,有点复杂了。我最初想的是通过自定义类加载器,破坏类加载固有的双亲委托机制。然后用特定的类加载器,去加载需要的类。保证先用类加载器内部的类,如果内部没有,才通过父加载器去加载。
最初这样做的目的,是这样指定容易。但是开发量,安全性,可读性都不高。因为这么做破坏了双亲委托机制,会导致类的多次加载。
在经过几次重构以后。最终确定的方案为:
将两个不同版本的jar包,放在一个中加件不能自动加载的地方,这样,整个应用中就没有对应的类。如果不加载,肯定是不能用的。解决这个问题的方法,就是在需要用到jar包内的类时。由指定的类去加载对应的jar包中的类。
就是在需要的时候由指定的类加载器加载指定的类。这样做的好处就是,没有破坏类的加载机制--双亲委托、保证了在区域内类的唯一性--即在使用某个类的上下文中,任何一个类只被加载过一次。至此,问题解决。