`
tigers20010
  • 浏览: 48431 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

2009-12-09休息 JAVA类加载器 (转载)

阅读更多

 

如果大家对文章内容有不理解的地方,尽情留言或QQ(1357208561) 讨论。让大家共同进步。

                                                                                                                                                                                                                                                                                               ————tigers20010




从张老师的基础增强课上,我就想深入了解一下类加载器。然后听懂了张老师的课,知道了JAVA类加载的方式,以及实现自己的类加载器的应用。但一直没有自己去编写类加载器,也对class文件的具体处理方式不了解。今日休息,有时间深入了解一下。







一、JAVA有三个类加载器:



1.bootstrap class loader,负责加载系统类,比如jdk的rt.jar包里的类。



2.extension class loader,负责加载jre/lib/ext目录下的所有类。



3.system class loader,负责加载环境变量classpath指向目录下的所有类。







他们三个依次是“父子关系”,因为bootstrap class loader一般是使用C语言编写的,所以用户无法获取它的对象。







当在classpath环境变量中的一个class文件被加载时,system class loader会将class交给父类extension class loader加载,extension class loader会将class交给bootstrap class loader加载。如果bootstrap class loader加载不了,则返回给extension class loader加载,如果extension class loader加载不了,则返回给system class loader加载。







被其中一个加载器成功加载后,便解析class文件。如果class文件中有使用到其他类对象,则继续调用类加载器加载。







有些情况下不希望被用户看到Class文件的明文,比如为了保护软件的安全、防止破解等。《JAVA核心技术第2卷》也有提到编写自己的类加载器,实现加载被加了密的class文件。







下面实现一个自己的类加载器,加载被加密了的class文件:







EasyTest.java用于被自定义类加载器加载。



public class EasyTest {



      public void print(){



            System.out.println("EasyTest,you did it!");



      }



}








Mycipher.java用于加密EasyTest.class。



package cn.itcast.cc.cipher;







import java.io.*;



import java.security.Key;



import javax.crypto.*;







public class MyCipher {



      private Key key = null;



      private String traninfo = null;







      public MyCipher(Key key, String traninfo) {



            this.key = key;



            this.traninfo = traninfo;



      }







      public void cipher(InputStream ins, OutputStream ous) throws IOException {



            // 创建加密输出流



            Cipher cip = null;



            CipherOutputStream cos = null;



            try {



                  cip = Cipher.getInstance(this.traninfo);



                  cip.init(Cipher.ENCRYPT_MODE, this.key);



                  cos = new CipherOutputStream(ous, cip);



                  // 写出到输入流



                  int len = 0;



                  byte[] buf = new byte[1024];



                  while ((len = ins.read(buf)) != -1) {



                        cos.write(buf, 0, len);



                  }



            } catch (Exception e) {



                  e.printStackTrace();



            } finally {



                  // 释放输入和输出流



                  cos.close();



                  ins.close();



                  ous.close();



            }



      }



}








MyClassLoader.java是自定义类加载器,用于解密被加密后的class文件。



package cn.itcast.cc.classloader;







import java.io.*;



import java.security.Key;



import javax.crypto.*;







public class MyClassLoader extends ClassLoader {



      private Key key = null;



      private String traninfo = null;







      public MyClassLoader(Key key, String traninfo) {



            this.key = key;



            this.traninfo = traninfo;



      }







      @Override



      @SuppressWarnings("unchecked")



      protected Class findClass(String name) throws ClassNotFoundException {



            // 获取class解密后的字节码



            byte[] classBytes = null;



            try {



                  classBytes = loadClassBytes(name);



            } catch (Exception e) {



                  throw new ClassNotFoundException(name);



            }



           



            // 使用字节码,实例类对象



            String clname = name.substring(name.lastIndexOf("/") + 1, name



                        .lastIndexOf("."));



            Class cl = defineClass(clname, classBytes, 0, classBytes.length);



            if (cl == null)



                  throw new ClassNotFoundException(name);



            return cl;



      }







      private byte[] loadClassBytes(String name) throws IOException {



            // 读入文件



            FileInputStream ins = null;



            ByteArrayOutputStream baos = null;



            CipherInputStream cis = null;



            byte[] result = null;



            try {



                  ins = new FileInputStream(name);



                  Cipher cip = Cipher.getInstance(this.traninfo);



                  cip.init(Cipher.DECRYPT_MODE, this.key);



                  // 使用密码解密class文件



                  cis = new CipherInputStream(ins, cip);



                  baos = new ByteArrayOutputStream();



                  int len = 0;



                  byte[] buf = new byte[1024];



                  while ((len = cis.read(buf)) != -1) {



                        baos.write(buf, 0, len);



                  }



                  result = baos.toByteArray();



            } catch (Exception e) {



                  e.printStackTrace();



            } finally {



                  // 释放流



                  baos.close();



                  cis.close();



                  ins.close();



            }







            return result;



      }



}








Test.java,用于测试自定义类加载器。



package cn.itcast.cc.testcalss;







import java.io.*;



import java.lang.reflect.Method;



import java.security.Key;



import javax.crypto.KeyGenerator;



import cn.itcast.cc.cipher.MyCipher;



import cn.itcast.cc.classloader.MyClassLoader;







public class Test {



      public static void main(String[] args) {



            KeyGenerator keyGen;



            try {



                  // 创建密钥



                  keyGen = KeyGenerator.getInstance("AES");



                  keyGen.init(128);



                  Key key = keyGen.generateKey();



                  keyGen = null;







                  MyCipher mc = new MyCipher(key,"AES/ECB/PKCS5Padding");



                  mc.cipher(new FileInputStream(new File("C:/EasyTestbak.class")),



                              new FileOutputStream(new File("C:/EasyTest.class")));







                  MyClassLoader mcl = new MyClassLoader(key,"AES/ECB/PKCS5Padding");



                 



                  Class clazz = mcl.loadClass("C:/EasyTest.class");



                  Method meth = clazz.getMethod("print", null);



                  meth.invoke(clazz.newInstance(), null);







            } catch (Exception e1) {



                  e1.printStackTrace();



            }



      }



}








注意:将EasyTest.java编译后放到C盘:C:/EasyTestbak.class







例子写的不干净,主要是为了演示自定义类加载器!







            学习了tomcat 和 servlet以来便对它们的实现机制比较感兴趣,虽然已经弄懂了他们简单的实现原理。但今日看到《实现自己的类加载器》这篇文章时,让对有了更深入的了解。在tomcat的webapps目录下的所有WEB应用中的class文件和jar文件,都是在Tomcat启动时将全路径记录到URLClassloader中。需要什么类,直接调用URLClassloader.loaderclass()方法即可!







            我原本想自己找到class文件的全路径,然后调用class.forname的方法不也可以吗?但如果有JAR包,我还需要使用JARInputstream读入,然后再搜索吗?这样太麻烦,所以还是使用URLClassloader比较好,它全处理了。

    它的实现原理,请看《实现自己的类加载器》 http://ajava.org/course/java/14990.html。











参考文献:《实现自己的类加载器》 http://ajava.org/course/java/14990.html


 

分享到:
评论

相关推荐

    自定义Java类加载器

    Java类加载器是Java虚拟机(JVM)的关键组成部分,它负责查找并加载类到内存中,使得程序能够运行。自定义Java类加载器允许我们根据特定需求扩展默认的加载机制,例如,从非标准位置加载类或者实现动态加载。在Java...

    Java类加载器.pdf

    ### Java类加载器详解 Java类加载器是Java运行时环境的一个关键组成部分,负责将类文件(.class)从各种来源加载到JVM中。它不仅管理类的生命周期,还确保了类的正确加载和初始化,是Java动态特性的基石。 #### 类...

    Java类加载内幕详细讲解

    通过掌握类加载的过程、类加载器的工作原理以及类加载的线程安全性等方面的知识,开发者能够更好地利用Java的动态特性,优化程序性能,并避免常见的异常问题,如`ClassNotFoundException`等。此外,对于自定义类加载...

    Java类加载器(ClassLoader)1

    Java类加载器分为三种主要类型:引导类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和应用程序类加载器(Application ClassLoader,也称为系统类加载器)。它们共同工作,确保了Java...

    深入研究Java类加载机制 深入研究Java类加载机制

    Java中的类加载器遵循一个原则叫做“父母委托模型”,即当一个类加载器收到类加载请求时,首先将加载任务委托给父类加载器,只有当父类加载器无法完成加载时才会尝试自己加载。 这种设计模式的好处在于避免了类的...

    Java类加载器机制与模型.pdf

    Java类加载器采用了**双亲委派模型(Parent Delegation Model)**,这意味着当一个类加载器收到加载类的请求时,它首先会委托其父类加载器去尝试加载,只有当父类加载器无法加载时,当前类加载器才会尝试自己加载。...

    Java类加载器学习总结.pdf

    Java类加载器是Java运行时环境(JRE)的一个重要组成部分,它负责将Java字节码加载到内存中,使其可以被Java虚拟机(JVM)执行。类加载器本身也是一个类,它的主要职责是从文件系统、网络或者JAR包中加载类文件到JVM...

    JAVA ClassLoader 讲解 (类加载器)

    ### Java ClassLoader (类加载器)详解 #### 一、教程提示 如果你正在查看这份文档,在线版中你可以点击下面的任何主题直接跳转到相应的部分。 1. **教程提示** 2. **介绍** 3. **类加载器结构** 4. **编译类加载...

    java的ClassLoader类加载器机制

    在 Java 中,类加载器的层次结构是固定的,引导类加载器 -> 扩展类加载器 -> 系统类加载器。每个类加载器都有其特定的加载范围和优先级,确保了 Java 类的正确加载和使用。 类加载器的工作原理可以分为三个阶段:...

    自定义类加载器实现自定义加载

    - Java中的类加载器采用双亲委派模型,即一个类首先由启动类加载器Bootstrap ClassLoader尝试加载,如果找不到则交给扩展类加载器Extension ClassLoader,再找不到则交由应用程序类加载器AppClassLoader,最后如果...

    Java虚拟机----类的加载过程.docx

    Java虚拟机(JVM)的类加载过程是Java程序运行的基础,它涉及到类加载器、类的生命周期和一系列复杂的步骤。在这个过程中,类加载器主要任务是根据类的全限定名加载二进制字节流并转化为`java.lang.Class`对象。整个...

    深入理解Java中的类加载器.pdf

    ### 深入理解Java中的类加载器 #### 一、引言 在Java编程语言中,类加载是一项至关重要的任务。它不仅涉及到程序的启动和执行,还直接影响着资源的管理和性能优化。本文将围绕《深入理解Java中的类加载器》这一...

    java类加载机制

    双亲委派模型是Java类加载器的重要特性之一,它的基本流程是:当一个类加载器收到加载类的请求时,它首先不会自己去尝试加载这个类,而是把请求委托给父类加载器去完成,每个层次的类加载器都是如此。如果父类加载器...

    Java 动态加载jar文件示例

    默认情况下,Java虚拟机(JVM)提供了三个内置的类加载器:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和应用程序类加载器(Application ClassLoader)。它们按照层次结构工作,...

    Java类加载内幕

    - **引导类加载器 (Bootstrap ClassLoader):** 这是 JVM 自带的类加载器,用于加载 Java 核心类库,如 `java.lang.*`。由于它是 JVM 内部的一部分,所以无法通过 Java API 直接访问。 - **扩展类加载器 (Extension ...

    JAVA-JVM-01类加载机制

    《JAVA-JVM-01类加载机制》 Java虚拟机(JVM)是Java程序运行的基础,其中类加载机制是其核心组成部分。本文将深入剖析Java中的类加载器和双亲委派机制,并通过示例讲解如何自定义类加载器。 类加载过程是Java程序...

    Java 类在 Tomcat 中是如何加载的(过程分析)

    JVM采用**父类委托机制**来加载类,这意味着当一个类加载器接收到加载请求时,它首先会委托给其父类加载器尝试加载,直到达到Bootstrap类加载器(顶级加载器)。如果父类加载器找不到所需类,那么请求会回溯到子类...

    JVM、Tomcat、OSGI等类加载器整理文档

    在Java世界中,类加载器(ClassLoader)是关键组件,它们负责将类的字节码加载到Java虚拟机(JVM)中。JVM、OSGI(Open Service Gateway Initiative)和Tomcat等容器都涉及到了类加载器的概念,理解它们的工作原理对...

    类加载的工具

    在Java编程语言中,类加载器(ClassLoader)是运行时环境的重要组成部分,它负责将类的字节码从各种来源(如硬盘、网络或内存)加载到Java虚拟机(JVM)中,使得程序能够执行。类加载工具则是辅助开发者理解和分析类...

    Java虚拟机JVM类加载初始化

    在Java中,类加载器(Classloader)扮演着核心角色。下面将详细讨论类加载的各个阶段以及相关的知识点。 1. 类加载(Load): 当Java虚拟机需要使用某个类时,首先会进行类加载。这通常涉及从磁盘、网络或压缩文件...

Global site tag (gtag.js) - Google Analytics