设为首页 加入收藏

TOP

JVM自定义类加载器加载指定classPath下的所有class及jar(一)
2018-10-10 04:11:23 】 浏览:247
Tags:JVM 定义 加载 指定 classPath 所有 class jar

一、JVM中的类加载器类型
  从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器。
  1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责JAVA_HOME/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作。
  2.其他类加载器:由java实现,可以在方法区找到其Class对象。这里又细分为几个加载器
    a).扩展类加载器(Extension ClassLoader):负责用于加载JAVA_HOME/lib/ext目录中的,或者被-Djava.ext.dirs系统变量指定所指定的路径中所有类库(jar),开发者可以直接使用扩展类加载器。java.ext.dirs系统变量所指定的路径的可以通过System.getProperty("java.ext.dirs")来查看。
    b).应用程序类加载器(Application ClassLoader):负责java -classpath或-Djava.class.path所指的目录下的类与jar包装入工作。开发者可以直接使用这个类加载器。在没有指定自定义类加载器的情况下,这就是程序的默认加载器。
    c).自定义类加载器(User ClassLoader):在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性。


  这四个类加载器的层级关系,如下图所示。
JVM自定义类加载器加载指定classPath下的所有class及jar


      


二、为什么要自定义类加载器
区分同名的类:假定在tomcat 应用服务器,上面部署着许多独立的应用,同时他们拥有许多同名却不同版本的类。要区分不同版本的类当然是需要每个应用都拥有自己独立的类加载器了,否则无法区分使用的具体是哪一个。
类库共享:每个web应用在tomcat中都可以使用自己版本的jar。但存在如Servlet-api.jar,java原生的包和自定义添加的Java类库可以相互共享。
加强类:类加载器可以在 loadClass 时对 class 进行重写和覆盖,在此期间就可以对类进行功能性的增强。比如使用javassist对class进行功能添加和修改,或者添加面向切面编程时用到的动态代理,以及 debug 等原理。
热替换:在应用正在运行的时候升级软件,不需要重新启动应用。比如toccat服务器中JSP更新替换。


三、自定义类加载器
  3.1 ClassLoader实现自定义类加载器相关方法说明
    要实现自定义类加载器需要先继承ClassLoader,ClassLoader类是一个抽象类,负责加载classes的对象。自定义ClassLoader中至少需要了解其中的三个的方法: loadClass,findClass,defineClass。
   


public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
protected final Class<?> defineClass(String name, byte[] b, int off, int len)
throws ClassFormatError
{
return defineClass(name, b, off, len, null);
}
    loadClass:JVM在加载类的时候,都是通过ClassLoader的loadClass()方法来加载class的,loadClass使用双亲委派模式。如果要改变双亲委派模式,可以修改loadClass来改变class的加载方式。双亲委派模式这里就不赘述了。
    findClass:ClassLoader通过findClass()方法来加载类。自定义类加载器实现这个方法来加载需要的类,比如指定路径下的文件,字节流等。
    definedClass:definedClass在findClass中使用,通过调用传进去一个Class文件的字节数组,就可以方法区生成一个Class对象,也就是findClass实现了类加载的功能了。


    贴上一段ClassLoader中loadClass源码,见见真面目...
   


protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}


}


    源码说明...


/**


   翻译过来大概是:使用指定的二进制名称来加载类,这个方法的默认实现按照以下顺序查找类: 调用findLoadedClass(String)方法检查这个类是否被加载过 使用父加载器调用loadClass(String)方法,如果父加载器为Null,类加载器装载虚拟机内置的加载器调用findClass(String)方法装载类, 如果,按照以上的步骤成功的找到对应的类,并且该方法接收的resolve参数的值为true,那么就调用resolveClass(Class)方法来处理类。 ClassLoader的子类最好覆盖findClass(String)而不是这个方法。 除非被重写,这个方法默认在整个装载过程中都是同步的(线程安全的)。


   resolveClass:Class载入必须链接(link),链接指的是把单一的Class加入到有继承关系的类树中。这个方法给Classloader用来链接一个类,如果这个类已经被链接过了,那么这个方法只做一个简单的返回。否则,这个类将被按照 Java?规范中的Execution描述进行链接。


 3.2 自定义类加载器实现
    按照3.1的说明,继承ClassLoader后重写了findClass方法加载指定路径上的class。先贴上自定义类加载器。


package com.chenerzhu.learning.classloader;


import java.nio.file.Files;
import java.nio.file.Paths;


/**


    


    以上就是自定义的类加载器了,实现的功能是加载指定路径的class。再看看如何使用。 


package com.chenerzhu.learning

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇JDK中注解的底层实现 下一篇Java程序语言的后门-反射机制

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目