Java实现的自定义类加载器示例

本文实例讲述了Java实现的自定义类加载器。分享给大家供大家参考,具体如下:

一 点睛

1 ClassLoader类有如下两个关键方法:

loadClass(String name, boolean resolve):该方法为ClassLoader的入口点,根据指定的二进制名称来加载类,系统就是调用ClassLoader的该方法来获取指定类对应的Class对象。

findClass(String name):根据二进制名称来查找类。

如果需要实现自定义的ClassLoader,可以通过重写以上两个方法来实现,当然我们推荐重写findClass()方法,而不是重写loadClass()方法。

2 自定义类加载器常用功能

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

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

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

根据应用需求把其他数据以字节码的形式加载到应用中。

二 实战

1 CompileClassLoader.java

import java.io.*;
import java.lang.reflect.*;
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];
   try(
      FileInputStream fin = new FileInputStream(file))
   {
     // 一次读取class文件的全部二进制数据
     int r = fin.read(raw);
     if(r != len)
      throw new IOException("无法读取全部文件:"
         + r + " != " + len);
     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(
           "ClassNotFoundExcetpion:" + 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();
     }
   }
   // 如果clazz为null,表明加载失败,则抛出异常
   if(clazz == null)
   {
     throw 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.length-1];
   System.arraycopy(args , 1 , progArgs
      , 0 , progArgs.length);
   CompileClassLoader ccl = new CompileClassLoader();
   // 加载需要运行的类
   Class<?> clazz = ccl.loadClass(progClass);
   // 获取需要运行的类的主方法
   Method main = clazz.getMethod("main" , (new String[0]).getClass());
   Object[] argsArray = {progArgs};
   main.invoke(null,argsArray);
  }
}

2 Hello.java

public class Hello
{
  public static void main(String[] args)
  {
   for (String arg : args)
   {
     System.out.println("运行Hello的参数:" + arg);
   }
  }
}

3 运行

E:\Java\疯狂java讲义\codes\18\18.2>java CompileClassLoader Hello 自定义加载器
CompileClassLoader:正在编译 Hello.java...
运行Hello的参数:自定义加载器

更多java相关内容感兴趣的读者可查看本站专题:《Java面向对象程序设计入门与进阶教程》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。

(0)

相关推荐

  • java类的加载过程以及类加载器的分析

    我们知道,我们写的java代码保存的格式是 .java, java文件被编译后会转换为字节码,字节码可以在任何平台通过java虚拟机来运行,这也是java能够跨平台的原因. 那JVM是如何来让我们写的java文件运行的呢? 这个问题通常的问法好像是:类是如何被加载的. 记得第一次遇见这个问题的时候,同学给我的回答是: 1.虚拟机会加载JDK里类的核心包 2.虚拟机会加载JDK里类的扩展包 3.虚拟机会加载JDK里类的系统包 4.虚拟机再会加载我们写好的java类. 初学的时候,大家都这么说,好像

  • java 详解类加载器的双亲委派及打破双亲委派

    java 详解类加载器的双亲委派及打破双亲委派 一般的场景中使用Java默认的类加载器即可,但有时为了达到某种目的又不得不实现自己的类加载器,例如为了达到类库的互相隔离,例如为了达到热部署重加载功能.这时就需要自己定义类加载器,每个类加载器加载各自的类库资源,以此达到资源隔离效果.在对资源的加载上可以沿用双亲委派机制,也可以打破双亲委派机制. 一.沿用双亲委派机制自定义类加载器很简单,只需继承ClassLoader类并重写findClass方法即可.如下例子: ①先定义一个待加载的类Test,它

  • 举例讲解Java的内部类与类的加载器

    内部类 class A { //Inner1 要在 A 初始化后 才能使用,即要被A的对象所调用 class Inner1 { int k = 0; // static int j = 0; //A加载后,Inner1没有加载,所以这个 静态变量j 无法立即使用,报错 final int z = 0; /*static void say1() { }*/ void say2() { } } //Inner2 在A加载好后就可以使用了 static class Inner2 { int k = 0

  • classloader类加载器_基于java类的加载方式详解

    基础概念 Classloader 类加载器,用来加载 Java 类到 Java 虚拟机中.与普通程序不同的是.Java程序(class文件)并不是本地的可执行程序.当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Java class加载到JVM里头运行,负责加载Java class的这部分就叫做Class Loader. JVM本身包含了一个ClassLoader称为Bootstrap ClassLoader,和JVM一样,BootstrapClassLoader是用本地代码实现

  • java 类加载与自定义类加载器详解

    类加载 所有类加载器,都是ClassLoader的子类. 类加载器永远以.class运行的目录为准. 读取classpath根目录下的文件有以下几种方式: 1 在Java项目中可以通过以下方式获取classspath下的文件: public void abc(){ //每一种读取方法,使用某个类获取Appclassloader ClassLoader cl = ReadFile.class.getClassLoader(); URL url = cl.getResource("a.txt&quo

  • 深入解析Java中的Class Loader类加载器

    类加载的过程 类加载器的主要工作就是把类文件加载到JVM中.如下图所示,其过程分为三步: 1.加载:定位要加载的类文件,并将其字节流装载到JVM中: 2.链接:给要加载的类分配最基本的内存结构保存其信息,比如属性,方法以及引用的类.在该阶段,该类还处于不可用状态: (1)验证:对加载的字节流进行验证,比如格式上的,安全方面的: (2)内存分配:为该类准备内存空间来表示其属性,方法以及引用的类: (3)解析:加载该类所引用的其它类,比如父类,实现的接口等. 3.初始化:对类变量进行赋值. 类加载器

  • Java语言中的自定义类加载器实例解析

    本文研究的主要是Java语言中的自定义类加载器实例解析的相关内容,具体如下. 自己写的类加载器 需要注意的是:如果想要对这个实例进行测试的话,首先需要在c盘建立一个c://myjava的目录.然后将相应的java文件放在这个目录中.并将产生的.clas文件放在c://myjava/com/lg.test目录下,否则是找不到的.这是要注意的.. class FileClassLoader : package com.lg.test; import java.io.ByteArrayOutputSt

  • java类加载器和类反射使用示例

    一.一个命令对应一个进程. 当我们启动一个Java程序,即启动一个main方法时,都将启动一个Java虚拟机进程,不管这个进程有多么复杂.而不同的JVM进程之间是不会相互影响的.这也就是为什么说,Java程序只有一个入口--main方法,让虚拟机调用.而两个mian方法,对应的是2个JVM进程,启动的是两个不同的类加载器,操作的实际上是不同的类.故而不会互相影响. 二.类加载. 当我们使用一个类,如果这个类还未加载到内存中,系统会通过加载.连接.初始化对类进行初始化. 1.类加载:指的是将类的c

  • java自定义类加载器代码示例

    如果要使用自定义类加载器加载class文件,就需要继承java.lang.ClassLoader类. ClassLoader有几个重要的方法: protectedClassLoader(ClassLoaderparent):使用指定的.用于委托操作的父类加载器创建新的类加载器. protectedfinalClass<?>defineClass(Stringname,byte[]b,intoff,intlen):将一个byte数组转换为Class类的实例. protectedClass<

  • Java实现的自定义类加载器示例

    本文实例讲述了Java实现的自定义类加载器.分享给大家供大家参考,具体如下: 一 点睛 1 ClassLoader类有如下两个关键方法: loadClass(String name, boolean resolve):该方法为ClassLoader的入口点,根据指定的二进制名称来加载类,系统就是调用ClassLoader的该方法来获取指定类对应的Class对象. findClass(String name):根据二进制名称来查找类. 如果需要实现自定义的ClassLoader,可以通过重写以上两

  • Java基础之自定义类加载器

    一.类加载器关系 自定义类加载器 创建一个类继承ClassLoader类,同时重写findClass方法,用于判断当前类的class文件是否已被加载 二.基于本地class文件的自定义类加载器 本地class文件路径 自定义类加载器: //创建自定义加载器类继承ClassLoader类 public class MyClassLoader extends ClassLoader{ // 包路径 private String Path; // 构造方法,用于初始化Path属性 public MyC

  • Java基于自定义类加载器实现热部署过程解析

    热部署: 热部署就是在不重启应用的情况下,当类的定义即字节码文件修改后,能够替换该Class创建的对象.一般情况下,类的加载都是由系统自带的类加载器完成,且对于同一个全限定名的java类,只能被加载一次,而且无法被卸载.可以使用自定义的 ClassLoader 替换系统的加载器,创建一个新的 ClassLoader,再用它加载 Class,得到的 Class 对象就是新的(因为不是同一个类加载器),再用该 Class 对象创建一个实例,从而实现动态更新.如:修改 JSP 文件即生效,就是利用自定

  • 浅谈Java自定义类加载器及JVM自带的类加载器之间的交互关系

    JVM自带的类加载器: 其关系如下: 其中,类加载器在加载类的时候是使用了所谓的"父委托"机制.其中,除了根类加载器以外,其他的类加载器都有且只有一个父类加载器. 关于父委托机制的说明: 当生成 一个自定义的类加载器实例时,如果没有指定它的父加载器,那么系统类加载器将成为该类加载器的父类加载器 下面,自定义类加载器.自定义的类加载器必须继承java.lang.ClassLoader类 import java.io.*; public class MyClassLoader extend

  • java自定义类加载器如何实现类隔离

    目录 自定义类加载器 准备 通过URLClassLoader来实现[推荐] 通过继承ClassLoader实现 网上java自定义类加载器很多容易找到,但是都是加载的单个类,如果被加载的类,有引用了其他类怎么办呢?接下来看一下如何来处理这种情况 有时候一个项目中可能会引用不同版本的第三方依赖,比如笔者在升级hbase系统时,代理层就同时用到了1.X和2.X版本的hbase-client的jar包. 当时是使用的阿里的SOFAArk来实现的. 它的本质就是是哟个类加载来实现的,接下来就通过一个小例

  • Java通过自定义类加载器实现类隔离

    目录 前言 类隔离是什么 使用场景 解决方案 重写findClass 重写loadClass 总结 前言 由于微服务的快速迭代.持续集成等特性,越来越多的团队更倾向于它.但是也体现出了一些问题,比如在基础设施建设过程中,需要把通用功能下沉,把现有大而全的基础设施按领域拆分,考虑需要兼容现有生产服务,会产生不同的依赖版本,有时不注意就可以引发问题.比如本文遇到的依赖包版本冲突问题,以及如何利用类隔离技术解决的分析. 类隔离是什么 类隔离是一种通过类加载器实现加载所需类的实现方式,使得不同版本类间隔

  • Java中线程上下文类加载器超详细讲解使用

    目录 一.什么是线程上下文类加载器 1.1.重要性 1.2.使用场景 二.ServiceLoader简单介绍 三.案例 3.1.使用ServiceLoader加载mysql驱动 3.2.Class.forName加载Mysql驱动 3.2.1.com.mysql.jdbc.Driver 3.2.2.java.sql.DriverManager初始化 3.2.3.调用DriverManager的registerDriver方法 3.2.4.执行DriverManager.getConnection

随机推荐