黑马程序员技术交流社区

标题: 关于自己写类加载器的问题 [打印本页]

作者: 姜胜凯    时间: 2014-1-22 20:33
标题: 关于自己写类加载器的问题
本帖最后由 姜胜凯 于 2014-1-26 16:12 编辑

假如我需要自己写一个类加载器。那么我写这个类需要实现什么??才会变成自己的类加载器~~~
求高手解答下自己如何写类加载器。


作者: 姜胜凯    时间: 2014-1-22 21:25
本帖最后由 姜胜凯 于 2014-1-23 16:41 编辑

。求大神解答我的自己写类加载器问题~~
作者: lgqioi    时间: 2014-1-24 17:01

自定义类加载器:

Public class CompileClassLoader extends ClassLoader

{

   //读取一个文件的内容

   Private byte[] getBytes(String filename) throws IOException

{

  File file = new File(filename);

  Long len = file.length();

  Byte[] raw = new byte[(int)len];

FileInputStream fin = new FileInuptStream(file);

//一次读取class文件的全部二进制数据

Int r = fin.read(raw);

If(r!=len)

Throw new IOException(“无法读取全部文件”+r+”!=”+len);

Fin.close();

Return raw;

}

//定义编译指定java文件的方法

Private Boolean compile(String javaFile) throws IOException

{

System.out.println(“CompileClassLoader:正在编译”+javaFile+”……..”);

//调用系统的javac命令

Process p = Runtime.getRuntime().exec(“javac”+javaFile);

Try{

      //其它线程都等待这个线程完成

      p.waitFor();

}catch(InterruptedException ie)

{

System.out.println(ie);

}

//获取javac 的线程的退出值

Int ret =p.exitValue();

//返回编译是否成功

Return  ret==0;

}

//重写Classloader的findCLass方法

Protected Class<?> findClass(String name)throws ClassNotFoundException

{

   Class clazz = null;

   //将包路径中的.替换成斜线/

String fileStub = name.replace(“.”,”/”);

String javaFilename = fileStub+”.java”;

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())

{



     Try{

  //如果编译失败,或该Class文件不存在

  If(!compile(javaFilename)||!classFile.exists())

{

Throw new ClassNotFoundException(“ClassNotFoundException:”+javaFilename);

}

}catch(IOException ex)

  {

     Ex.printStackTrace();

}

}           

//如果class文件存在,系统负责将该文件转化成class对象

If(classFile.exists())

{

  Try{

     //将class文件的二进制数据读入数组

    Byte[] raw= getBytes(classFilename);

   //调用Classloader的defineClass方法将二进制数据转换成class对象

   Clazz = defineClass(name,raw,0.raw.length);

}catch(IOException ie)

{

  Ie.printStackTrace();

}

}

//如果claszz为null,表明加载失败,则抛出异常

If(clazz==null){

   Thow new ClassNotFoundException(name);

}

Return clazz;

}



//定义一个主方法

Public static void main(String [] args )throws Exception

{

//如果运行该程序时没有参数,即没有目标类

  If(args.length<1){

      System.out.println(“缺少运行的目标类,请按如下格式运行java源文件:”);

      System.out.println(“java CompileClassLoader ClassName”);

}

//第一个参数是需要运行的类

String progClass = args[0];

//剩下的参数将作为运行目标类时的参数,所以将这些参数复制到一个新数组中

String progargs[] = new String [args.leng-1];

Sytem.arraycopy(args,1,progargs,0,progArgs.length);

CompileClassLoader cl = new CompileClassLoader();

//加载需要运行的类

Class<?> clazz = cl.loadClass(progClass);

//获取需要运行的类的主方法

Method main= clazz.getMethod(“main”,(new String[0]).getClass());

Object argsArray[] = {progargs};

Main.invoke(null,argsArray);

}

}

自定义加载器实现如下功能:

执行代码前自动验证数字签名

根据用户提供的密码解密代码,从而可以实现代码混淆器来避免反编译class文件

根据用户需求来动态的加载类

根据应用需求把其他数据以字节码的形式加载到应用中
作者: lgqioi    时间: 2014-1-24 17:02
以上是网上查阅的

作者: IT人    时间: 2014-1-24 21:21
编写一个自己的类加载器需要注意三点:
1.ClassLoader这个基类
2.不用覆盖loaderClass()这个方法,因为覆盖了loaderClass()这个方法,你就把具体流程给覆盖了,可能你自己还要写找上级加载器的代码比较麻烦
3.而我们只要完成每个继承ClassLoader这个的子类具体代码就行了,所以只覆盖findClass()方法,这样你的类加载器的classloader()方法还有委托机制

代码:
class MyClassLoader extends ClassLoader
{

public MyClassLoader(String classDir){
this.classDir = classDir;
}
protected Class findClass(String name)throws Exception
{
String classFileName = classDir + "\\" + name + ".class";
try{
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int b = -1;
while((b = fis.read()) != -1){
bos.write(b)
}
fis.close();
byte[] bytes = bos.toByteArray();
return defineClass(bytes,0,bytes.length);
}
catch(Exception e){
e.printStackTrace();
}
return null;
}

}




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2