博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自定义类加载器
阅读量:6523 次
发布时间:2019-06-24

本文共 3719 字,大约阅读时间需要 12 分钟。

虽然在绝大多数情况下,系统默认提供的类加载器实现已经可以满足需求。但是在某些情况下,您还是需要为应用开发出自己的类加载器。比如您的应用通过网络来传输 Java 类的字节代码,为了保证安全性,这些字节代码经过了加密处理。这个时候您就需要自己的类加载器来从某个网络地址上读取加密后的字节代码,接着进行解密和验证,最后定义出要在 Java 虚拟机中运行的类来。下面将通过两个具体的实例来说明类加载器的开发。

下面,详细的介绍自定义一个类加载器的过程。

一、首先,写出一个接口,然后用一个类实现该接口,该类作为测试类,即我们自定义ClassLoader要加载的类。

接口:

1 /**2  * 要加载类的接口,加载该接口的子类时,可以用接口引用,而不需要利用反射来实现。3  */4 public interface InterfaceTest {5     public void name();6     public void age();7 }

测试类:

1 /** 2  * 测试类,自定义类加载器去加载该类 3  */ 4 public class ClassTest implements InterfaceTest{ 5  6     @Override 7     public void name() { 8         System.out.println("tao"); 9     }10 11     @Override12     public void age() {13         System.out.println("21");14     }15 16 }

二、自定义一个加密类,用来加密测试类的字节码文件。

 

找到我们要加密的.class文件的位置:E:\workspace.fu\ClassLoaderTest\bin\com\tao\test\ClassTest.class

加密后的.class文件要存储的位置,这里将它直接放到E盘根目录:E:\ClassTest.class

1 /** 2  * 用加密算法生成要隐藏的字节码文件 3  */ 4 public class ClassEncrypt extends MyClassLoader{ 5     public static void main(String[] args) throws IOException { 6         //要加密的字节码.class文件 7         String srcPath="E:/workspace.fu/ClassLoaderTest/bin/com/tao/test/ClassTest.class"; 8         //加密之后输出的字节码.class文件的位置 9         String destPath="E:/ClassTest.class";10         FileInputStream fis=new FileInputStream(srcPath);11         FileOutputStream ofs=new FileOutputStream(destPath);12         cypher(fis, ofs);//加密13         fis.close();14         ofs.close();15     }16     17     //简单的加密,用于测试。将所有二进制位取反,即0变成1,1变成018     private static void cypher(InputStream in,OutputStream out) throws IOException{19         int b=-1;20         while((b=in.read())!=-1){21             out.write(b^0xff);22         }23     }24 }

运行该类,那么,我们就已经对ClassTest.class文件加密成功,打开E盘,可以发现根目录下已经有了一个ClassTest.class文件。

 

可以将E:\workspace.fu\ClassLoaderTest\bin\com\tao\test的ClassTest.class文件删除,并且删除ClassTest.java文件和加密类ClassEncrypt.java。

 

三、编写我们自己的类加载器,必须继承ClassLoader,然后覆盖findClass()方法。

ClassLoader超类的loadClass方法用于将类的加载操作委托给父类加载器去进行,只有该类尚未加载并且父类加载器也无法加载该类时,才调用findClass()方法。

如果要实现该方法,必须做到以下几点:

(1)、为来自本地文件系统或者其他来源的类加载其字节码

(2)、调用ClassLoader超类的defineClass()方法,向虚拟机提供字节码

1 /** 2  * 自定义的类加载器 3  */ 4 public class MyClassLoader extends ClassLoader{ 5      6     /** 7      * 因为类加载器是基于委托机制,所以我们只需要重写findClass方法。 8      * 它会自动向父类加载器委托,如果父类没有找到,就会再去调用我们重写的findClass方法加载 9      */10     @Override11     protected Class
findClass(String name) throws ClassNotFoundException {12 try {13 //需要加载的.class字节码的位置14 String classPath="E:/ClassTest.class";15 16 FileInputStream fis=new FileInputStream(classPath);17 ByteArrayOutputStream bos=new ByteArrayOutputStream();18 cypher(fis, bos);19 fis.close();20 byte[] bytes=bos.toByteArray();21 return defineClass(bytes, 0, bytes.length);22 } catch (FileNotFoundException e) {23 e.printStackTrace();24 } catch (IOException e) {25 e.printStackTrace();26 }27 return super.findClass(name);28 }29 30 //相应的字节码解密类,在加载E盘根目录下的被加密过的ClassTest.class字节码的时候,进行相应的解密。31 private static void cypher(InputStream in,OutputStream out) throws IOException{32 int b=-1;33 while((b=in.read())!=-1){34 out.write(b^0xff);35 }36 }37 }

四、最后写一个测试类,测试我们的类加载器

1 public class Test {2     public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {3         Class clazz=new MyClassLoader().loadClass("com.tao.test.ClassTest");4             //这就是我们接口的作用。如果没有接口,就需要利用反射来实现了。5             InterfaceTest classTest=(InterfaceTest) clazz.newInstance();6         classTest.name();7         classTest.age();8     }9 }

 

 

 

转载地址:http://lkjbo.baihongyu.com/

你可能感兴趣的文章
云服务器 ECS 使用OpenAPI管理ECS:使用OpenAPI弹性创建ECS实例
查看>>
写个软件来防止服务器网站CPU百分百
查看>>
智能城市里,“公共电话亭”的存在意味着什么?
查看>>
JVM分代垃圾回收策略的基础概念
查看>>
《交互式程序设计 第2版》一3.5 捕获简单用户交互行为
查看>>
5G技术的5大猜想
查看>>
MongoDB 3.0(1):CentOS7 安装MongoDB 3.0服务
查看>>
别随便安装 Pokemon GO被曝藏恶意后门
查看>>
让数据会思考会说话,为出海企业提供多样化数据智能解决方案
查看>>
我眼中的自动化测试框架设计要点
查看>>
FLIF:自由的无损图像格式
查看>>
Google开源Inception-ResNet-v2,提升图像分类水准
查看>>
Opera 出售细节曝光:昆仑出资1.68亿美元
查看>>
CentOS 5.3 下快速安装配置 PPTP ××× 服务器
查看>>
产品经理学习总结之技术和设计篇
查看>>
23种设计模式(15):备忘录模式
查看>>
java基础学习总结——IO流
查看>>
iOS获取APP ipa 包以及资源文件
查看>>
CentOS 7 关闭启动防火墙
查看>>
Vue-选项卡切换
查看>>