第一步: 给你一个编译好的class文件以及它的包名,创建一个对象出来。
1)class文件源代码
package com.wsc.classloader; public class Tool{ public void print() { } }
2)使用javac Tool.java 编译成class文件
3)将Tool.class文件读取到内存中,生成byte[]数组
/** * 加载class文件 * * @param clazzPath * class绝对文件路径 * @return 字节数组 * @throws IOException */ private byte[] loadClassFile(String clazzPath) throws IOException { FileInputStream fis = new FileInputStream(clazzPath); BufferedInputStream bis = new BufferedInputStream(fis); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024 * 256]; int ch = 0; while ((ch = bis.read(buffer, 0, buffer.length)) != -1) { baos.write(buffer, 0, ch); } return baos.toByteArray(); }
4)自定义ClassLoader,使用ClassLoader中的defineClass方法:protected final Class<?> defineClass(String name, byte[] b, int off, int len)。参数分别是类名称,class文件对应的字节数组,起始位置和终止位置。
@Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); if (c == null) { c = defineClass(name, data, 0, data.length); } return c; }
整体代码是:
package com.wsc.classloader; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; public class ClassLoaderOne extends ClassLoader { public static void main(String[] args) throws Exception { ClassLoaderOne loader = new ClassLoaderOne( "E:\\JAVA\\JAVAFX\\ClassLoader\\libs\\Tool.class"); Class<?> clazz = loader.loadClass("com.wsc.classloader.Tool"); Object o = clazz.newInstance(); System.out.println(o.getClass().getClassLoader()); } private byte[] data; public ClassLoaderOne(String clazzPath) throws IOException { data = loadClassFile(clazzPath); } /** * 加载class文件 * * @param clazzPath * class绝对文件路径 * @return 字节数组 * @throws IOException */ private byte[] loadClassFile(String clazzPath) throws IOException { FileInputStream fis = new FileInputStream(clazzPath); BufferedInputStream bis = new BufferedInputStream(fis); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024 * 256]; int ch = 0; while ((ch = bis.read(buffer, 0, buffer.length)) != -1) { baos.write(buffer, 0, ch); } return baos.toByteArray(); } @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); if (c == null) { c = defineClass(name, data, 0, data.length); } return c; } }
感觉是这样的,跑一下:
Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang at java.lang.ClassLoader.preDefineClass(Unknown Source) at java.lang.ClassLoader.defineClass(Unknown Source) at java.lang.ClassLoader.defineClass(Unknown Source) at com.wsc.classloader.ClassLoaderOne.loadClass(ClassLoaderOne.java:52) at java.lang.ClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(Unknown Source) at java.lang.ClassLoader.defineClass(Unknown Source) at com.wsc.classloader.ClassLoaderOne.loadClass(ClassLoaderOne.java:52) at java.lang.ClassLoader.loadClass(Unknown Source) at com.wsc.classloader.ClassLoaderOne.main(ClassLoaderOne.java:14)
意思是:禁止加载名为java.lang的包。
原因是:虽然Tool类中没有使用任何引入java.lang下类,但是它的父类Object是在java.lang下的,classloader加载Tool类时会把它所有的关系网都加载出来才行,父类Object肯定是要加载的。
这样就简单了!无非多写一个If else.使用父加载器(类加载器都有一个父类加载器)加载即可。
@Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); if (name.equals("java.lang.Object")) { ClassLoader parent = getParent(); c = parent.loadClass(name); } if (c == null) { c = defineClass(name, data, 0, data.length); } return c; }
跑一下结果是:
com.wsc.classloader.ClassLoaderOne@ca470
第二步:新的问题
Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; i++) { String name = methods[i].getName(); System.out.println(name); Class<?>[] params = methods[i].getParameterTypes(); for (int j = 0; j < params.length; j++) { System.out.println(params[j].toString()); } }
这个时候还是会报刚才的错误,因为Method类也在java.lang包下,只能在增加一个If else.
显然,代码应该这样写
@Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); if (c == null) { // 如果父加载器不为null,使用父类加载器加载(比如Object,HashMap等核心类) if (getParent() != null) { try { c = getParent().loadClass(name); } catch (Exception e) { // 父类可能没加载,则抛异常 } } // 如果父类加载器没有加载,再使用自定义加载器加载 if (c == null) { c = defineClass(name, data, 0, data.length); } } return c; }
打印结果:
toString print class java.lang.String getClass hashCode equals class java.lang.Object notify notifyAll wait long int wait wait long com.wsc.classloader.ClassLoaderOne@fcfa52
第三步:如果本地可以通过.class文件创建,远程当然也已同一个道理(如果需要加密,在本地多一个解密即可)。如果class文件是远程调用的话,本地一般使用接口或者反射两种方法调用。首选是接口,反射一是效率,而是要清楚所有的方法名称、参数名称过于麻烦。
由于远程加载class文件到本地,如果出错很难定位出错位置。幸好,classloader使用规则默认是根据URLClassLoader来使用的,会先根据检查本地是否有该类,所以可以直接将源码放在本地即可调试,当然发布的时候一定要删除。
如图:
通过这个基本的入门程序可以了解ClassLoader的基本流程。
相关推荐
那么,如果要在程序退出之前能动态的实时 加载修改后编译出来的新的.class文件中的效果,则需要创建动态对象,如同Tomcat中的热部署效果一样。 于是,专门创建动态对象的工具包DynaObject产生了。 DynaObject...
换言之,每当编写并且编译了一个新类,就会产生一个Class对象(恰当地说,是被保存在一个同名的.class文件中)。在运行时,当我们想生成这个类的对象时,运行这个程序的 Java虚拟机(JVM)首先检查这个类的Class对象...
2.1 Class文件格式 ................................................. 21 2.2 数据类型 ...................................................... 22 2.3 原始类型与值 ............................................
我们创建一个类,通过编译,生成对应的.calss文件,之后使用java.exe加载(jvm的类加载器)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在缓存区,那么这个运行时类的本身就是一个class的实例 ...
根据xml文件生成C# 属性class类,附件含源码。分享给需要的朋友
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的 ...
1 .3 .5 Class Info 标签..................... 24 1 .4 建立第一个Windows应用程序.................. 24 1 .4 .1 建立应用程序框架................... 25 1 .4 .2 应用程序代码分析................... 31 1 .4 ....
它是所有converter中最简单的,就象调用java的静态方法一样,所以并不需要创建对象. 默认的时候DWR将java void值转换成javascript的null值就是这样设置<convert converter="null" match="void"/>. 有时java.lang.Void...
2.1 Class文件格式 ................................................. 21 2.2 数据类型 ...................................................... 22 2.3 原始类型与值 ............................................
2.2.3 把选中对象定义为板框外形 ........................................................................................ 25 2.2.4 从 DXF 文件定义板框外形..................................................
VBScript作为脚本语言不仅能够编写简单的脚本,而且还能够创建及使用对象编写复杂的脚本,如Class对象,数据字典,操作文件夹及文件,错误处理,正则表达式等等。1.Class对象2.Dictionary对象 VBScript作为脚本...
<!-- TOC --> - Mybatis源码分析 - 1. 解析配置文件,创建SQLSessionFactory - 2.... - 3. 获取mapper代理对象: ...这一步首先读取了mybatis的configuration xml配置文件,用这个流构造了Factory的Builder,它底
只要在创建对象时,为构造方法提供三个参数,包括创建验证码图片的宽度、高度及验证码字母个数,就可以成功创建一个验证码类的对象。在脚本code.php中,使用session_start()开启用户会话控制,然后包含验证码类Vcode...
10、使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? .................................................................................................................................
2.2.1 创建示例库 ......................................................................................................26 2.2.2 创建模式及表 ..............................................................
1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM ........................
baigo SSO单点登录系统,一款基于 HTTP ... 1、将下载到的程序包解压,然后将所有文件上传到服务器,假设网站 URL 为 你的域名 上传到根目录,以下说明均以此为例; 2、用浏览器打开 您的域名/install/ 按提示操作。
为音频文件创建进度搜索条 8.5节. 融合两幅图像 8.6节. 将Convolution滤镜应用于图像 8.7节. 通过摄像头将视频发送到FMS实例 8.8节. 访问用户的麦克风并创建声音显示 8.9节. 在Flex程序中平滑播放视频 8.10节. 检测...
用反射原理 从配置文件中读取数据 public static void main(String[] args) throws Exception{ Properties pro=new Properties(); pro.load(new FileInputStream("fanshe.txt")); //Class c=null; String ...
请生成相应的getter、setter方法,并创建两个构造方法:Person(),Person(String idNo),把Person编译成.class文件。请通过反射技术,抽取Person所有的属性、方法,重新拼接成源文件字符串,再将字符串写入到一个新...