如果大家对文章内容有不理解的地方,尽情留言或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运行时环境的一个关键组成部分,负责将类文件(.class)从各种来源加载到JVM中。它不仅管理类的生命周期,还确保了类的正确加载和初始化,是Java动态特性的基石。 #### 类...
Java的类加载器是Java虚拟机(JVM)的核心组件之一,它负责将类的字节码从磁盘、网络或其他数据源加载到内存中,并转换为可执行的Java对象。类加载器不仅关乎程序的运行,还在实现动态加载、插件系统等方面发挥着...
Java应用程序类加载器是Java平台的核心组成部分之一,它负责加载应用程序中的类到JVM(Java虚拟机)中,使得程序能够执行。理解类加载器的工作原理对于深入学习Java编程至关重要。在Java中,类加载器按照层次结构...
Java类加载器是Java虚拟机(JVM)的重要组成部分,它的主要职责是将类的字节码文件(.class文件)从文件系统、网络或内存中读取,并转换为运行时的java.lang.Class对象。这个过程是Java动态加载机制的核心,使得Java...
2. Extension ClassLoader:扩展类加载器,负责加载`<JAVA_HOME>/lib/ext`目录下的扩展类库,或者被`-Djava.ext.dirs`指定的路径中的类。 3. Application ClassLoader:也称为系统类加载器,负责加载用户类路径`-cp...
Java类加载器采用了**双亲委派模型(Parent Delegation Model)**,这意味着当一个类加载器收到加载类的请求时,它首先会委托其父类加载器去尝试加载,只有当父类加载器无法加载时,当前类加载器才会尝试自己加载。...
### 深入探讨Java类加载器 #### 类加载器基本概念 类加载器(Class Loader)是Java语言的关键组成部分之一,它负责将Java类的字节码加载到Java虚拟机(JVM)中,从而使得Java应用程序能够运行起来。自Java诞生以来...
Java 类加载器有三种默认使用的类加载器:Bootstrap 类加载器、Extension 类加载器和 System 类加载器(或称作 Application 类加载器)。每种类加载器都有设定好从哪里加载类。 Bootstrap 类加载器负责加载 rt.jar ...
Java的类加载机制:加载,连接,初始化。JAVA类加载器: Bootstrap ClassLoader : 根类加载器, Extension ClassLoader: 扩展类加载器, System ClassLoader : 系统类加载器, Java反射
在Java编程语言中,类加载器(ClassLoader)是运行时环境的重要组成部分,它负责加载类的字节码到JVM中。这篇博文“JAVA类加载器分析--热部署的缺陷”探讨了Java类加载机制以及在热部署场景下可能遇到的问题。热部署...
Java加壳技术是一种保护Java程序不被轻易反编译或篡改的安全手段,它通过自定义类加载器来实现对原始字节码的包装。在Java中,类加载器是负责加载类到JVM(Java虚拟机)的核心组件。自定义类加载器允许开发者根据...
默认情况下,Java虚拟机(JVM)提供了三个内置的类加载器:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和应用程序类加载器(Application ClassLoader)。它们按照层次结构工作,...
- **引导类加载器 (Bootstrap ClassLoader):** 这是 JVM 自带的类加载器,用于加载 Java 核心类库,如 `java.lang.*`。由于它是 JVM 内部的一部分,所以无法通过 Java API 直接访问。 - **扩展类加载器 (Extension ...
《JAVA-JVM-01类加载机制》 Java虚拟机(JVM)是Java程序运行的基础,其中类加载机制是其核心组成部分。本文将深入剖析Java中的类加载器和双亲委派机制,并通过示例讲解如何自定义类加载器。 类加载过程是Java程序...
Java标准类加载器包括Bootstrap ClassLoader(引导类加载器)、Extension ClassLoader(扩展类加载器)和AppClassLoader(应用程序类加载器)。此外,用户还可以自定义类加载器以满足特定的加载需求。 总的来说,...
每个`Class`实例都关联着一个特定的类加载器,若加载器为`null`,则表示类由引导类加载器(bootstrap loader)加载,这是最基础的加载器,由JVM内置,非Java编写。 自定义类加载器(Custom ClassLoader)允许开发...
"Java面试题-内存+GC+类加载器+JVM调优" 在 Java 面试中,内存、GC、类加载器和 JVM 调优是非常重要的知识点,本文将对这些知识点进行详细的解释和分析。 一、Java 内存模型 在 Java 中,内存主要分为两部分:堆...
- 自定义类加载器需要继承Java的`java.lang.ClassLoader`类,并重写`findClass()`方法。在这个方法中,我们可以添加解析JAR或ZIP包的逻辑。 - 当需要加载一个类时,类加载器会调用`loadClass(String name)`方法。...