文档章节

JAVA自定义类加载器

墙头草
 墙头草
发布于 2011/07/18 09:56
字数 713
阅读 338
收藏 1

JAM中除了根加载器外,其他的加载器都是继承的ClassLoader。所以开发者可以定义自己的类加载器,然后重写ClassLoader的方法。通过查看API可以知道,ClassLoader有许多protected方法,这些都是可以用来重写的。

ClassLoader有几个重要方法:

findClass(String name);根据二进制类文件名来查找类

loadClass(String name,boolean resolve);该方法为ClassLoader的入口点,根据指定的二进制名称来加载类

但是一般推荐覆写第一个方法。

下面介绍自己写的ClassLoader

/**
 * @author:LYL
 * @date:2011-7-17,下午01:02:47
 * @description:自定义ClassLoader
 */
package com.lyl.reflect;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class CompileClassLoader extends ClassLoader {
    // 读入源文件转换为字节数组
    private byte[] getSource(String filename) {
        File file = new File(filename);
        int length = (int) file.length();
        byte[] contents = new byte[length];
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            int r = fis.read(contents);
            if (r != length) {
                throw new IOException("IOException:无法读取" + filename);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return contents;
    }

    // 编译文件
    public boolean compile(String javaFile) {
        System.out.println("正在编译" + javaFile);
        int ret = 0;
        try {
            // 调用系统命令编译文件
            Process process = Runtime.getRuntime().exec("javac " + javaFile);
            process.waitFor();
            ret = process.exitValue();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return ret == 0;
    }

    // 重写findclass
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> clazz = null;
        // 将文件的.替换为/,例如com.lyl.reflect.Reflect被替换为com/lyl/reflect/Reflect
        String fileStub = name.replace(".", "/");
        // java源文件名
        String javaFileName = fileStub + ".java";
        // 编译后的class文件名
        String classFileName = fileStub + ".class";
        File javaFile = new File(javaFileName);
        File classFile = new File(classFileName);
        // 当指定JAVA源文件存在,且class文件不存在,
        // 或者java源文件的修改时间比class文件修改时间晚则重新编译
        if (javaFile.exists()
                && (!classFile.exists() || javaFile.lastModified() > classFile
                        .lastModified())) {
            // 如果编译失败,或者class文件不存在
            if (!compile(javaFileName) || !classFile.exists()) {
                throw new ClassNotFoundException("ClassNotFoundException:"
                        + javaFileName);
            }
        }
        // 如果CLASS文件按存在,系统负责将该文件转换成Class对象
        if (classFile.exists()) {
            byte[] raw = getSource(classFileName);
            // 将ClassLoader的defineClass方法将二进制数据转换成Class对象
            int divindex = name.indexOf("\\");
            String javafilename = null;
            // 如果是某个盘里面的文件,要去掉文件的盘符
            if (divindex != -1) {
                javafilename = name.substring(divindex + 1, name.length());
            }
            // 将字节数组转换为class实例
            clazz = defineClass(javafilename, raw, 0, raw.length);
        }
        // 如果clazz为null,表明加载失败,则抛出异常
        if (clazz == null) {
            throw new ClassNotFoundException(name);
        }
        return clazz;
    }

    // 定义主方法
    public static void main(String[] args) throws ClassNotFoundException,
            SecurityException, NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {
        // 如果运行该程序没有参数,则没有目标类
        if (args.length < 1) {
            System.out.println("缺少运行的目标类,请按如下格式运行源文件");
            System.out.println("java CompileClassLoader ClassName");
            System.exit(0);
        }
        // 第一个参数为需要运行的类
        String proClass = args[0];
        // 剩下的参数将作为目标类得参数
        String[] proArgs = new String[args.length - 1];
        System.arraycopy(args, 1, proArgs, 0, proArgs.length);Java多线程Queue总结
        CompileClassLoader ccl = new CompileClassLoader();
        // 加载需要运行的类
        Class<?> clazz = ccl.loadClass(proClass);
        Method main = clazz.getMethod("main", (new String[0]).getClass());
        Object[] argsArray = { proArgs };
        main.invoke(null, argsArray);
    }
}

© 著作权归作者所有

下一篇: JBoss Resteasy
墙头草
粉丝 16
博文 145
码字总数 117172
作品 0
卢湾
私信 提问
Java的classloader

类加载器的基本概念 类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被...

huzorro
2012/12/18
1K
0
JVM自定义类加载器加载指定classPath下的所有class及jar

一、JVM中的类加载器类型   从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器。   1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责JAVAH...

Ala6
2018/10/04
0
0
java classloader 过程

jvm classLoader architecture : a, Bootstrap ClassLoader/启动类加载器 主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作. b, Extension ClassLoader/扩......

Idiot_s_Sky
2014/01/19
156
0
深入浅出 ClassLoader

内容概述 “类加载”介绍 “类加载器”介绍 深入“类加载器” 深入“父亲委托机制” 一,“类加载”介绍 “加载”是类加载的时机的第一阶段。 类从被加载到虚拟机内存中开始,到卸载出内存为...

tomas家的小拨浪鼓
08/04
0
0
Java Classloader机制解析

做Java开发,对于ClassLoader的机制是必须要熟悉的基础知识,本文针对Java ClassLoader的机制做一个简要的总结。因为不同的JVM的实现不同,本文所描述的内容均只限于Hotspot Jvm. 本文将会从...

aminqiao
2014/05/09
24K
2

没有更多内容

加载失败,请刷新页面

加载更多

TiDB 最佳实践系列(三)乐观锁事务

作者:Shirly TiDB 最佳实践系列是面向广大 TiDB 用户的系列教程,旨在深入浅出介绍 TiDB 的架构与原理,帮助用户在生产环境中最大限度发挥 TiDB 的优势。我们将分享一系列典型场景下的最佳实...

TiDB
25分钟前
5
0
原来缓存是这样

经过一闪而过的一个灵感,记下来,我觉得缓存的定义应该是这样定义的: 我之前一直认为缓存的词义是错误的:是在读取到值之后,再次被使用的时候,不会去取新的值,而是使用旧的值,这是是错...

走向人生巅峰的大路
27分钟前
4
0
数字货币交易所开发常用的7个开源撮合引擎

如果你希望按照自己的需求打造金融交易平台,那么应当选择合适的交易撮合引擎进行二次开发而不是基于完整的交易平台实现进行修改。本文将介绍10个采用不同语言开发的开源的撮合引擎,你可以根...

汇智网教程
30分钟前
5
0
Spring Security做JWT认证和授权

Spring Security做JWT认证和授权

乐逍遥-镜子
32分钟前
5
0
LNMP---日志不记录静态文件、日志切割、静态文件过期缓存、nginx防盗链

4.39 日志不记录静态文件 4.40 日志切割 4.41 静态文件过期缓存 4.42 nginx防盗链 扩展: yum install lrzsz -yrz 上传文件sz filename 这样去把这个文件推送到windows上 一、日志不记录...

tobej
43分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部