ClassLoader 初步

与普通程序不一样的是,Java程序(class文件)并非本地的可执行程序。当运行Java程序时,首先运行JVM(Java虚拟机),而后再把 Java class加载到JVM里头运行,负责加载Java class的这部分就叫作Class Loader。   JVM自己包含了一个ClassLoader称为Bootstrap ClassLoader,和JVM同样,BootstrapClassLoader是用本地代码实现的,它负责加载核心JavaClass(即全部 java.*开头的类)。另外JVM还会提供两个ClassLoader,它们都是用Java语言编写的,由BootstrapClassLoader加 载;其中Extension ClassLoader负责加载扩展的Javaclass(例如全部javax.*开头的类和存放在JRE的ext目录下的 类),ApplicationClassLoader负责加载应用程序自身的类。   当运行一个程序的时候,JVM启动,运行bootstrapclassloader,该 ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),而后调用 ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的 加载流程。   注: 学ClassLoader看OSGIjava

何时加载类?

   何时JVM会使用ClassLoader加载一个类呢?当你使用java去执行一个类,JVM使用ApplicationClassLoader加 载这个类;而后若是类A引用了类B,不论是直接引用仍是用Class.forName()引用,JVM就会找到加载类A的ClassLoader,并用这 个ClassLoader来加载类B。JVM按照运行时的有效执行语句,来决定是否须要装载新类,从而装载尽量少的类,这一点和编译类是不相同的。   Why use your own ClassLoader?   彷佛JVM自身的ClassLoader已经足够了,为何咱们还须要建立本身的ClassLoader呢?   由于JVM自带的ClassLoader只是懂得从本地文件系统加载标准的java class文件,若是编写你本身的ClassLoader,你能够作到:   1)在执行非置信代码以前,自动验证数字签名   2)动态地建立符合用户特定须要的定制化构建类   3)从特定的场所取得java class,例如数据库中   4) 等等   事实上当使用Applet的时候,就用到了特定的ClassLoader,由于这时须要从网络上加载java class,而且要检查相关的安全信息。   目前的应用服务器大都使用了ClassLoader技术,即便你不须要建立本身的ClassLoader,了解其原理也有助于更好地部署本身的应用。web

类加载器的树状结构 & 委托代理模式

   当你决定建立你本身的ClassLoader时,须要继承java.lang.ClassLoader或者它的子类。在实例化每一个 ClassLoader对象时,须要指定一个父对象;若是没有指定的话,系统自动指定 ClassLoader.getSystemClassLoader()为父对象。   因此当建立本身的Class Loader时,只须要重载findClass()这个方法。数据库

卸载? 重载?

   当一个javaclass被加载到JVM以后,它有没有可能被卸载呢?咱们知道Win32有FreeLibrary()函数,Posix有 dlclose()函数能够被调用来卸载指定的动态链接库,可是Java并无提供一个UnloadClass()的方法来卸载指定的类。   在Java中,java class的卸载仅仅是一种对系统的优化,有助于减小应用对内存的占用。既然是一种优化方法,那么就彻底是JVM自行决定如何实现,对Java开发人员来 说是彻底透明的。   在何时一个java class/interface会被卸载呢?Sun公司的原话是这么说的:"class or interfacemay be unloaded if and only if its class loader is unreachable. Classesloaded by the bootstrap loader may not be unloaded."   事实上咱们关心的不是如何卸载类的,咱们关心的是如何更新已经被加载了的类从而更新应用的功能。JSP则是一个很是典型的例子,若是一个JSP文件被 更改了,应用服务器则须要把更改后的JSP从新编译,而后加载新生成的类来响应后继的请求。   其实一个已经加载的类是没法被更新的,若是你试图用同一个ClassLoader再次加载同一 个类,就会获得异常(java.lang.LinkageError: duplicate classdefinition),咱们只可以从新建立一个新的ClassLoader实例来再次加载新类。至于原来已经加载的类,开发人员没必要去管它, 由于它可能还有实例正在被使用,只要相关的实例都被内存回收了,那么JVM就会在适当的时候把不会再使用的类卸载。   使用线程上下文类加载器, 能够在执行线程中, 抛弃双亲委派加载链模式, 使用线程上下文里的类加载器加载类.   典型的例子有, 经过线程上下文来加载第三方库jndi实现, 而不依赖于双亲委派.   大部分java app服务器(jboss, tomcat..)也是采用contextClassLoader来处理web服务。   固然, 好东西都有利弊. 使用线程上下文加载类, 也要注意, 保证多根须要通讯的线程间的类加载器应该是同一个, 防止由于不一样的类加载器, 致使类型转换异常(ClassCastException).bootstrap

相关文章
相关标签/搜索