读书人

Java类加载器入门运用

发布时间: 2012-08-22 09:50:35 作者: rapoo

Java类加载器入门应用

1、类加载器负责加载 Java 类的字节代码到 Java 虚拟机中。最初是为了满足 Java Applet的需要而开发出来的,
? Java Applet需要从远程下载Java类文件到浏览器中并执行。类加载器使得Java类可以被动态加载到Java虚拟机中并执行。


2、基本上所有的类加载器都是java.lang.ClassLoader类的一个实例,java.lang.ClassLoader类的基本职责
就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java类,
即java.lang.Class类的一个实例。除此之外,ClassLoader还负责加载Java应用所需的资源,
如图像文件和配置文件等。
ClassLoader中与加载类相关的方法如下:
(1)getParent() 返回该类加载器的父类加载器。?
(2)loadClass(String name) 加载名称为 name的类。
(3)findClass(String name) 查找名称为 name的类。
(4)findLoadedClass(String name) 查找名称为 name的已经被加载过的类。
(5)defineClass(String name, byte[] b, int off, int len) 把字节数组 b中的内容转换成 Java类。
(6)resolveClass(Class<?> c) 链接指定的 Java 类。

?

3、java虚拟机中可以安装多个类加载,系统默认三个主要类加载器,每个类负责加载特定位置的类:
(1)引导类加载器(BootStrp):
?? 它用来加载 Java的核心库,是用C++来实现的,并不继承自 java.lang.ClassLoader,
?? 主要加载目录JRE/lib/rt.jar
(2)扩展类加载器(ExtClassLoader):
??? 它用来加载 Java 的扩展库。主要加载目录JRE/lib/ext/*.jar。
(3)系统类加载器(AppClassLoader):
?? 它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类,主要加载目录CLASSPATH指定的所有jar或目录。
? Java 应用的类都是由它来完成加载的,可以通过 ClassLoader.getSystemClassLoader()来获取它。


4. 除了引导类加载器(BootStrp)之外,所有的类加载器都有一个父类加载器。可通过getParent()方法得到父类加载器。
?? JDK 的实现对于父类加载器是引导类加载器(BootStrp)的情况,getParent()方法返回 null。例:

public class FileSystemClassLoader extends ClassLoader {     private String rootDir;     public FileSystemClassLoader(String rootDir) {         this.rootDir = rootDir;     }     protected Class<?> findClass(String name) throws ClassNotFoundException {         byte[] classData = getClassData(name);         if (classData == null) {             throw new ClassNotFoundException();         }         else {             return defineClass(name, classData, 0, classData.length);         }     }     private byte[] getClassData(String className) {         String path = classNameToPath(className);         try {             InputStream ins = new FileInputStream(path);             ByteArrayOutputStream baos = new ByteArrayOutputStream();             int bufferSize = 4096;             byte[] buffer = new byte[bufferSize];             int bytesNumRead = 0;             while ((bytesNumRead = ins.read(buffer)) != -1) {                 baos.write(buffer, 0, bytesNumRead);             }             return baos.toByteArray();         } catch (IOException e) {             e.printStackTrace();         }         return null;     }     private String classNameToPath(String className) {         return rootDir + File.separatorChar                 + className.replace('.', File.separatorChar) + ".class";     } }

?

8.Tomcat6的类加载器(从上至下)
(1)BootStrapClassLoader,Java的核心库,实际没有这个类
(2)ExtensionClassLoader,对于Sun JVM,是sun.misc.Launcher$ExtClassLoader,加载 Java 的扩展库。?????????????????????
(3) SystemClassLoader,对于Sun JVM,是sun.misc.Launcher$AppClassLoader,加载java的应用库。?????????????????????
(4) CommonClassLoader,对于Tomcat 6,是org.apache.catalina.loader.StandardClassLoader,
加载的类目录通过{tomcat}/conf/catalina.properties中的common.loader指定,
以SystemClassLoader为parent(目前默认定义是common.loader=${catalina.base}/lib,
${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar)
(5) CatalinaClassLoader,加载的类目录通过{tomcat}/conf/catalina.properties中server.loader指定,
?以CommonClassLoader为parent,如果server.loader配置为空,
?则ServerClassLoader 与CommonClassLoader是同一个(默认server.loader配置为空)
(6)?SharedClassLoader:加载的类目录通过{tomcat}/conf/catalina.properties中share.loader指定,
?以CommonClassLoader为parent,如果server.loader配置为空,
?则CatalinaClassLoader 与CommonClassLoader是同一个(默认share.loader配置为空)
(7)?WebappClassLoader:每个Context一个WebappClassLoader实例,
?负责加载context的/WEB-INF/lib和/WEB-INF/classes目录,
?context间的隔离就是通过不同的WebappClassLoader来做到的。
?由于类定义一旦加载就不可改变,因此要实现tomcat的context的reload功能,
?实际上是通过新建一个新的WebappClassLoader来做的,
?因此reload的做法实际上代价是很高昂的,需要注意的是,JVM内存的Perm区是只吃不拉的,
?抛弃掉的WebappClassLoader加载的类并不会被JVM释放,
?因此tomcat的reload功能如果应用定义的类比较多的话,reload几次就OutOfPermSpace异常了。
(8)JasperLoader:每个JSP一个JasperLoader实例,与WebappClassLoader做法类似,
JSP支持修改生效是通过丢弃旧的JasperLoader,建一个新的JasperLoader来做到的,
同样的,存在轻微的PermSpace的内存泄露的情况。

?

读书人网 >编程

热点推荐