本文目录导读:

我来为您提供一个全面的Java类加载器案例,包括基本概念演示、自定义类加载器实现以及应用场景。
基础类加载器演示
import java.net.URL;
import java.net.URLClassLoader;
/**
* 类加载器基础案例
*/
public class ClassLoaderBasicDemo {
public static void main(String[] args) throws Exception {
// 获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("系统类加载器: " + systemClassLoader);
// 获取扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println("扩展类加载器: " + parent);
// 获取引导类加载器(通常为null)
ClassLoader bootstrap = parent.getParent();
System.out.println("引导类加载器: " + bootstrap);
// 查看类的加载器
Class<?> stringClass = String.class;
System.out.println("String类加载器: " + stringClass.getClassLoader());
Class<?> demoClass = ClassLoaderBasicDemo.class;
System.out.println("Demo类加载器: " + demoClass.getClassLoader());
// 查看类加载器的加载路径
URL[] urls = ((URLClassLoader) systemClassLoader).getURLs();
System.out.println("\n系统类加载器加载路径:");
for (URL url : urls) {
System.out.println(" - " + url);
}
}
}
自定义类加载器
import java.io.*;
import java.nio.file.*;
import java.security.MessageDigest;
/**
* 自定义类加载器 - 支持加密解密
*/
public class CustomClassLoader extends ClassLoader {
private final String classPath;
private final String encryptionKey; // 简单示例,实际应该使用更安全的方式
public CustomClassLoader(String classPath, String encryptionKey) {
this.classPath = classPath;
this.encryptionKey = encryptionKey;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 将点号转成路径分隔符
String path = name.replace('.', '/').concat(".class");
File file = new File(classPath, path);
if (!file.exists()) {
throw new ClassNotFoundException("类文件不存在: " + name);
}
try {
byte[] classBytes = loadClassData(file);
// 解密类字节码
classBytes = decrypt(classBytes, encryptionKey);
// 定义类
return defineClass(name, classBytes, 0, classBytes.length);
} catch (Exception e) {
throw new ClassNotFoundException("加载类失败: " + name, e);
}
}
/**
* 加载class文件字节码
*/
private byte[] loadClassData(File file) throws IOException {
try (FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
return bos.toByteArray();
}
}
/**
* 简单的XOR加密/解密
*/
private byte[] decrypt(byte[] data, String key) {
byte[] keyBytes = key.getBytes();
byte[] result = new byte[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = (byte) (data[i] ^ keyBytes[i % keyBytes.length]);
}
return result;
}
/**
* 加密class文件
*/
public static void encryptClassFile(File sourceFile, File targetFile, String key)
throws IOException {
byte[] classData = Files.readAllBytes(sourceFile.toPath());
byte[] encryptedData = new byte[classData.length];
byte[] keyBytes = key.getBytes();
for (int i = 0; i < classData.length; i++) {
encryptedData[i] = (byte) (classData[i] ^ keyBytes[i % keyBytes.length]);
}
Files.write(targetFile.toPath(), encryptedData);
System.out.println("加密完成: " + targetFile.getPath());
}
}
热部署类加载器
import java.io.*;
import java.net.*;
import java.util.*;
/**
* 支持热部署的类加载器
*/
public class HotDeployClassLoader extends URLClassLoader {
private final String className;
private final String classPath;
private Map<String, Long> classModifiedTimes = new HashMap<>();
public HotDeployClassLoader(String className, String classPath) {
super(new URL[0], HotDeployClassLoader.class.getClassLoader());
this.className = className;
this.classPath = classPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 只负责加载指定的类及其依赖
if (!name.equals(className)) {
return super.findClass(name);
}
try {
String path = name.replace('.', '/').concat(".class");
File file = new File(classPath, path);
if (!file.exists()) {
throw new ClassNotFoundException("类文件不存在: " + name);
}
byte[] classData = Files.readAllBytes(file.toPath());
return defineClass(name, classData, 0, classData.length);
} catch (IOException e) {
throw new ClassNotFoundException("无法加载类: " + name, e);
}
}
/**
* 检查类文件是否被修改
*/
public boolean isClassModified() {
try {
String path = className.replace('.', '/').concat(".class");
File file = new File(classPath, path);
if (!file.exists()) {
return false;
}
long lastModified = file.lastModified();
Long previousModified = classModifiedTimes.get(className);
if (previousModified == null || previousModified != lastModified) {
classModifiedTimes.put(className, lastModified);
return true;
}
return false;
} catch (Exception e) {
return false;
}
}
}
热部署演示程序
import java.io.*;
import java.lang.reflect.Method;
/**
* 热部署演示
*/
public class HotDeployDemo {
private static final String CLASS_PATH = "./temp";
private static final String CLASS_NAME = "com.example.DynamicService";
public static void main(String[] args) throws Exception {
// 创建模拟的动态服务类源码
createTestClass();
compileTestClass();
// 加载并执行
loadAndExecute();
// 模拟修改代码
Thread.sleep(2000);
modifyTestClass();
compileTestClass();
// 再次加载并执行(热部署)
loadAndExecute();
}
private static void loadAndExecute() {
try {
HotDeployClassLoader loader = new HotDeployClassLoader(CLASS_NAME, CLASS_PATH);
// 检查类是否被修改
if (loader.isClassModified()) {
System.out.println("检测到类文件更新,重新加载...");
}
Class<?> clazz = loader.loadClass(CLASS_NAME);
Object instance = clazz.getDeclaredConstructor().newInstance();
Method method = clazz.getMethod("getVersion");
String version = (String) method.invoke(instance);
Method method2 = clazz.getMethod("greet", String.class);
String greeting = (String) method2.invoke(instance, "World");
System.out.println("版本: " + version);
System.out.println("问候: " + greeting);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void createTestClass() throws IOException {
File dir = new File("./src");
dir.mkdirs();
String code = """
package com.example;
public class DynamicService {
public String getVersion() {
return "v1.0.0";
}
public String greet(String name) {
return "Hello, " + name + "! (v1)";
}
}
""";
File sourceFile = new File("./src/com/example/DynamicService.java");
sourceFile.getParentFile().mkdirs();
Files.write(sourceFile.toPath(), code.getBytes());
}
private static void modifyTestClass() throws IOException {
String code = """
package com.example;
public class DynamicService {
public String getVersion() {
return "v2.0.0";
}
public String greet(String name) {
return "Hello, " + name + "! (v2 - updated)";
}
}
""";
File sourceFile = new File("./src/com/example/DynamicService.java");
Files.write(sourceFile.toPath(), code.getBytes());
// 复制到 class path
Files.copy(sourceFile.toPath(),
Path.of(CLASS_PATH, "com/example/DynamicService.java"),
StandardCopyOption.REPLACE_EXISTING);
}
}
插件系统架构
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
/**
* 插件管理器 - 演示动态加载插件
*/
public class PluginManager {
private final Map<String, Class<?>> plugins = new ConcurrentHashMap<>();
private final Map<String, ClassLoader> loaders = new ConcurrentHashMap<>();
private final String pluginPath;
public PluginManager(String pluginPath) {
this.pluginPath = pluginPath;
}
/**
* 加载所有插件
*/
public void loadPlugins() {
File dir = new File(pluginPath);
if (!dir.exists() || !dir.isDirectory()) {
System.out.println("插件目录不存在: " + pluginPath);
return;
}
for (File jarFile : dir.listFiles((d, name) -> name.endsWith(".jar"))) {
loadPlugin(jarFile);
}
}
/**
* 加载单个插件
*/
public void loadPlugin(File jarFile) {
try {
// 创建URLClassLoader
URL url = jarFile.toURI().toURL();
URLClassLoader loader = new URLClassLoader(new URL[]{url},
this.getClass().getClassLoader());
// 扫描jar包中的插件类
try (JarFile jar = new JarFile(jarFile)) {
jar.stream()
.filter(e -> e.getName().endsWith(".class"))
.filter(e -> !e.getName().contains("$"))
.forEach(e -> {
try {
String className = e.getName()
.replace('/', '.')
.replace(".class", "");
// 加载并验证是否为插件
Class<?> clazz = loader.loadClass(className);
if (isPlugin(clazz)) {
String pluginName = getPluginName(clazz);
plugins.put(pluginName, clazz);
loaders.put(pluginName, loader);
System.out.println("成功加载插件: " + pluginName);
}
} catch (Exception ex) {
// 忽略无法加载的类
}
});
}
} catch (Exception e) {
System.err.println("加载插件失败: " + jarFile.getName());
e.printStackTrace();
}
}
/**
* 创建插件实例
*/
public <T> T createPlugin(String pluginName, Class<T> pluginType) {
Class<?> clazz = plugins.get(pluginName);
if (clazz == null) {
throw new IllegalArgumentException("插件不存在: " + pluginName);
}
try {
return pluginType.cast(clazz.getDeclaredConstructor().newInstance());
} catch (Exception e) {
throw new RuntimeException("创建插件实例失败", e);
}
}
/**
* 卸载插件
*/
public void unloadPlugin(String pluginName) {
plugins.remove(pluginName);
ClassLoader loader = loaders.remove(pluginName);
if (loader instanceof URLClassLoader) {
try {
((URLClassLoader) loader).close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("卸载插件: " + pluginName);
}
/**
* 判断是否为有效的插件类
*/
private boolean isPlugin(Class<?> clazz) {
return clazz.isAnnotationPresent(Plugin.class) ||
interfacesContainPlugin(clazz);
}
/**
* 检查接口
*/
private boolean interfacesContainPlugin(Class<?> clazz) {
for (Class<?> iface : clazz.getInterfaces()) {
if (iface.getName().contains("Plugin") ||
iface == PluginInterface.class) {
return true;
}
}
return false;
}
/**
* 获取插件名称
*/
private String getPluginName(Class<?> clazz) {
Plugin annotation = clazz.getAnnotation(Plugin.class);
if (annotation != null && !annotation.name().isEmpty()) {
return annotation.name();
}
return clazz.getSimpleName();
}
// 插件注解
public @interface Plugin {
String name() default "";
}
// 插件接口
public interface PluginInterface {
void execute();
}
}
/**
* 插件演示类
*/
@PluginManager.Plugin(name = "demo-plugin")
public class DemoPlugin implements PluginManager.PluginInterface {
@Override
public void execute() {
System.out.println("执行演示插件...");
System.out.println("插件类加载器: " + this.getClass().getClassLoader());
System.out.println("插件父加载器: " + this.getClass().getClassLoader().getParent());
}
}
类加载器隔离案例
import java.lang.reflect.Method;
import java.net.URLClassLoader;
import java.io.File;
/**
* 类加载器隔离演示
*/
public class ClassLoaderIsolationDemo {
public static void main(String[] args) throws Exception {
System.out.println("=== 类加载器隔离演示 ===\n");
// 演示1:相同类名的不同版本
demonstrateSameClassDiffVersions();
// 演示2:父子类加载器可见性
demonstrateParentChildVisibility();
// 演示3:线程上下文类加载器
demonstrateContextClassLoader();
}
private static void demonstrateSameClassDiffVersions() throws Exception {
System.out.println("--- 演示1:同一个类在不同类加载器中的隔离 ---");
File version1Dir = new File("./lib/version1");
File version2Dir = new File("./lib/version2");
// 创建两个独立的类加载器
URLClassLoader loader1 = new URLClassLoader(
new java.net.URL[]{version1Dir.toURI().toURL()});
URLClassLoader loader2 = new URLClassLoader(
new java.net.URL[]{version2Dir.toURI().toURL()});
// 加载同一个类
Class<?> class1 = loader1.loadClass("com.example.VersionedService");
Class<?> class2 = loader2.loadClass("com.example.VersionedService");
System.out.println("类1的加载器: " + class1.getClassLoader());
System.out.println("类2的加载器: " + class2.getClassLoader());
System.out.println("它们是不同的类(实例): " + (class1 != class2));
// 创建实例并调用方法
Object obj1 = class1.getDeclaredConstructor().newInstance();
Object obj2 = class2.getDeclaredConstructor().newInstance();
Method method1 = class1.getMethod("getVersion");
Method method2 = class2.getMethod("getVersion");
System.out.println("版本1: " + method1.invoke(obj1));
System.out.println("版本2: " + method2.invoke(obj2));
// 注意:类型不能互转
System.out.println("对象类型不同: " + (obj1.getClass() != obj2.getClass()));
// 关闭加载器
loader1.close();
loader2.close();
}
private static void demonstrateParentChildVisibility() throws Exception {
System.out.println("\n--- 演示2:父子类加载器的可见性 ---");
// 创建子类加载器
URLClassLoader childLoader = new URLClassLoader(
new java.net.URL[]{new File("./custom").toURI().toURL()},
ClassLoader.getSystemClassLoader()
);
// 子加载器可以看到父加载器的类
try {
Class<?> stringClass = childLoader.loadClass("java.lang.String");
System.out.println("子加载器可以加载String: " + stringClass);
} catch (ClassNotFoundException e) {
System.out.println("无法加载String");
}
// 但是使用双亲委派模型
Class<?> customClass = childLoader.loadClass("com.example.CustomClass");
System.out.println("用户类的加载器: " + customClass.getClassLoader());
// 验证双亲委派
System.out.println("自定义类加载器委派给父加载器: " +
(customClass.getClassLoader() == ClassLoader.getSystemClassLoader()));
childLoader.close();
}
private static void demonstrateContextClassLoader() throws Exception {
System.out.println("\n--- 演示3:线程上下文类加载器 ---");
// 获取当前线程
Thread thread = Thread.currentThread();
System.out.println("当前线程: " + thread.getName());
System.out.println("原始的上下文加载器: " + thread.getContextClassLoader());
// 创建新类加载器并设置为上下文加载器
URLClassLoader customLoader = new URLClassLoader(
new java.net.URL[]{new File("./context").toURI().toURL()},
thread.getContextClassLoader()
);
// 修改线程上下文加载器
thread.setContextClassLoader(customLoader);
System.out.println("修改后的上下文加载器: " + thread.getContextClassLoader());
// 使用上下文加载器加载类
Class<?> clazz = Thread.currentThread()
.getContextClassLoader()
.loadClass("com.example.ContextService");
System.out.println("通过上下文加载器加载的类: " + clazz.getClassLoader());
// 恢复原始的上下文加载器
thread.setContextClassLoader(thread.getContextClassLoader().getParent());
System.out.println("恢复后的上下文加载器: " + thread.getContextClassLoader());
customLoader.close();
}
}
实际应用案例:插件式加密解密框架
import java.util.*;
import java.lang.reflect.*;
import java.util.concurrent.*;
/**
* 可扩展的算法框架 - 通过类加载器动态加载不同的算法实现
*/
public class AlgorithmFramework {
// 算法接口
public interface Algorithm {
String getName();
String encrypt(String data);
String decrypt(String encryptedData);
}
private final Map<String, Algorithm> algorithms = new ConcurrentHashMap<>();
private final Map<String, ClassLoader> algorithmLoaders = new ConcurrentHashMap<>();
private final String algorithmPath;
public AlgorithmFramework(String algorithmPath) {
this.algorithmPath = algorithmPath;
loadDefaultAlgorithms();
}
/**
* 加载默认算法
*/
private void loadDefaultAlgorithms() {
// 内置算法 - AES
registerAlgorithm("AES", new AESAlgorithm());
// 内置算法 - Caesar
registerAlgorithm("Caesar", new CaesarAlgorithm());
}
/**
* 注册算法
*/
public void registerAlgorithm(String name, Algorithm algorithm) {
algorithms.put(name, algorithm);
System.out.println("注册算法: " + name);
}
/**
* 动态加载算法插件
*/
public void loadAlgorithmPlugin(String jarFilePath, String className) {
try {
// 创建独立类加载器
URLClassLoader loader = new URLClassLoader(
new java.net.URL[]{new File(jarFilePath).toURI().toURL()},
this.getClass().getClassLoader()
);
// 加载算法类
Class<?> clazz = loader.loadClass(className);
// 验证是否是算法实现
if (!Algorithm.class.isAssignableFrom(clazz)) {
throw new IllegalArgumentException("类 " + className + " 不是Algorithm的实现");
}
// 创建实例并注册
Algorithm algorithm = (Algorithm) clazz.getDeclaredConstructor().newInstance();
registerAlgorithm(algorithm.getName(), algorithm);
algorithmLoaders.put(algorithm.getName(), loader);
} catch (Exception e) {
throw new RuntimeException("加载算法插件失败: " + className, e);
}
}
/**
* 卸载算法插件
*/
public void unloadAlgorithm(String name) {
Algorithm algorithm = algorithms.remove(name);
if (algorithm != null) {
ClassLoader loader = algorithmLoaders.remove(name);
System.out.println("卸载算法: " + name);
if (loader instanceof URLClassLoader) {
try {
((URLClassLoader) loader).close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 获取算法
*/
public Algorithm getAlgorithm(String name) {
Algorithm algorithm = algorithms.get(name);
if (algorithm == null) {
throw new IllegalArgumentException("未知算法: " + name);
}
return algorithm;
}
/**
* 使用指定算法加密
*/
public String encrypt(String algorithmName, String data) {
Algorithm algorithm = getAlgorithm(algorithmName);
return algorithm.encrypt(data);
}
/**
* 使用指定算法解密
*/
public String decrypt(String algorithmName, String encryptedData) {
Algorithm algorithm = getAlgorithm(algorithmName);
return algorithm.decrypt(encryptedData);
}
/**
* 列出所有可用算法
*/
public Set<String> listAlgorithms() {
return algorithms.keySet();
}
// 内置AES算法实现(简化版)
private static class AESAlgorithm implements Algorithm {
@Override
public String getName() {
return "AES";
}
@Override
public String encrypt(String data) {
// 简化的加密实现(实际应用中应该使用标准AES)
return "AES加密(" + data + ")";
}
@Override
public String decrypt(String encryptedData) {
// 简化的解密实现
return encryptedData.substring(5, encryptedData.length() - 1);
}
}
// 内置Caesar算法实现
private static class CaesarAlgorithm implements Algorithm {
private static final int SHIFT = 3;
@Override
public String getName() {
return "Caesar";
}
@Override
public String encrypt(String data) {
return shift(data, SHIFT);
}
@Override
public String decrypt(String encryptedData) {
return shift(encryptedData, -SHIFT);
}
private String shift(String data, int shift) {
StringBuilder result = new StringBuilder();
for (char c : data.toCharArray()) {
if (Character.isLetter(c)) {
char base = Character.isUpperCase(c) ? 'A' : 'a';
result.append((char) ((c - base + shift + 26) % 26 + base));
} else {
result.append(c);
}
}
return result.toString();
}
}
public static void main(String[] args) throws Exception {
System.out.println("=== 算法框架演示 ===\n");
// 创建框架
AlgorithmFramework framework = new AlgorithmFramework("./algorithms");
// 列出内建算法
System.out.println("内建算法: " + framework.listAlgorithms());
// 使用AES算法
String data = "Hello World";
String aesEncrypted = framework.encrypt("AES", data);
String aesDecrypted = framework.decrypt("AES", aesEncrypted);
System.out.println("\nAES加密: " + aesEncrypted);
System.out.println("AES解密: " + aesDecrypted);
// 使用Caesar算法
String caesarEncrypted = framework.encrypt("Caesar", data);
String caesarDecrypted = framework.decrypt("Caesar", caesarEncrypted);
System.out.println("\nCaesar加密: " + caesarEncrypted);
System.out.println("Caesar解密: " + caesarDecrypted);
// 动态加载第三方算法插件(如果有)
if (new File("./algorithms/my-algorithm.jar").exists()) {
System.out.println("\n正在加载第三方算法...");
framework.loadAlgorithmPlugin("./algorithms/my-algorithm.jar",
"com.custom.CustomAlgorithm");
System.out.println("加载后的算法: " + framework.listAlgorithms());
}
// 实现算法接口的示例插件类
createExamplePlugins();
}
private static void createExamplePlugins() {
// 这里可以创建示例插件类
// 实际项目中可以通过反射动态加载
}
}
核心要点总结
类加载器的双亲委派机制
public class ParentDelegationDemo {
public static void main(String[] args) throws Exception {
// 双亲委派的完整流程
ClassLoader bootstrap = null; // Bootstrap ClassLoader (JVM原生)
ClassLoader platform = ClassLoader.getPlatformClassLoader(); // Platform
ClassLoader system = ClassLoader.getSystemClassLoader(); // System
ClassLoader custom = new CustomClassLoader(""); // 自定义
// 层级关系
System.out.println("自定义的父加载器: " + custom.getParent());
System.out.println("系统加载器的父加载器: " + system.getParent());
// 委派流程演示
System.out.println("\n双亲委派流程:");
System.out.println("1. Custom加载器尝试加载类");
System.out.println("2. 委托给Parent: System");
System.out.println("3. System委托给Parent: Platform");
System.out.println("4. Platform委托给Bootstrap");
System.out.println("5. Bootstrap找到类则返回,否则向下委托");
System.out.println("6. 最终由Custom尝试加载");
// 实际验证
Class<?> clazz = custom.loadClass("java.lang.String");
System.out.println("\n加载String类的实际加载器: " + clazz.getClassLoader());
// 输出null,因为String由Bootstrap加载
}
}
类加载器的最佳实践
public class BestPracticesDemo {
/**
* 正确获取类加载器的模式
*/
public static ClassLoader getBestClassLoader() {
// 1. 线程上下文类加载器(推荐用于框架)
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl != null) {
return cl;
}
// 2. 当前类加载器(推荐用于插件)
cl = BestPracticesDemo.class.getClassLoader();
if (cl != null) {
return cl;
}
// 3. 系统类加载器(最后的选择)
return ClassLoader.getSystemClassLoader();
}
/**
* 资源加载的注意事项
*/
public static void loadResources() {
// 使用getResourceAsStream而不是getResource
try (InputStream is = BestPracticesDemo.class
.getClassLoader()
.getResourceAsStream("config.properties")) {
// 处理资源
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 避免的常见错误
*/
public static void avoidCommonMistakes() {
// 错误1:硬编码类加载器
// ClassLoader cl = ClassLoader.getSystemClassLoader(); // 不推荐
// 错误2:省略null检查
// 应该先获取线程上下文类加载器并检查null
// 错误3:在静态初始化中加载外部类
// 应该在方法中按需加载
// 错误4:不处理ClassNotFoundException
// 总是捕获或声明抛出
}
}
这些案例展示了Java类加载器的核心概念和实际应用,通过学习和实践这些示例,您将能够:
- 理解类加载器的基本概念和层级结构
- 自定义类加载器实现特殊加载逻辑
- 实现热部署功能
- 构建插件化的系统架构
- 理解并正确使用双亲委派模型
- 避免类加载器相关的常见问题
建议在实际项目中根据需求选择适当的类加载器模式,并注意内存管理和类加载器的正确使用。