上文学习了Java类加载相关基本知识。
本文举例一个简单例子(自定义类加载,加密解密,再通过反射的机制调用)。
其实类似JSP原理
package com.test;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
/**
* @author Sahinn
* @date 16/4/16
* 自定义ClassLoader
* 主要是从网络获取来的字节流,进行某种加密解密之后来创建类对象
* 比如对http://src.zuobin.net/net/zuobin/netclass/decodeTest.class进行加密解密
* 当然可以提供带参数的,校验的,返回class字节流的服务,这样某些代码就可以存放在服务器端
*/
public class NetDecodeClassLoader extends ClassLoader {
private String netPath;
private String packageName="net.zuobin.netclass";
//设置某种加密方式,加密key等
private String decodeStyle;
private String decodeKey;
//配置网络地址
public NetDecodeClassLoader(String netPath,String decodeStyle,String decodeKey) {
this.netPath = netPath;
this.decodeStyle = decodeStyle;
this.decodeKey = decodeKey;
}
protected byte[] deCode(byte[] bytes){
//进行具体的解密,校验操作等等
//比如base64等
return bytes;
}
private byte[] getData(String className){
//可以带验证key,https等等
String path = this.netPath + File.separator + className.replace('.',File.separatorChar) + ".class";
try {
URL url = new URL(path);
InputStream in = url.openStream();
OutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int num = 0;
while ((num = in.read(buffer)) != -1){
byteArrayOutputStream.write(buffer,0,num);
}
return ((ByteArrayOutputStream)byteArrayOutputStream).toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> aclass = findLoadedClass(name);
//查询是否已加载
if (aclass != null) {
return aclass;
}
//指定具体的包下的类需要从网络里面获取,然后解密
if (packageName.startsWith(name)) {
byte[] data = getData(name);
byte[] decodedata = this.deCode(data);
if (decodedata == null) {
throw new ClassNotFoundException();
}else {
return defineClass(name,decodedata,0,decodedata.length);
}
}
//如果不是该包里面的类,直接返回父类的类加载机制
return super.findClass(name);
}
}
注意点:
JVM在加载类之前会检查类是否已被加载(findLoadedClass()),如果已被加载再调用loadClass就好出错。
JVM判断类是否是同一个有两个条件
判断类名包名是否是同一个
加载这个ClassLoader的实例对象是否是同一个,注意是实例对象
由于大量使用动态类加载会增加JVM的PermGen区,只有Full GC时候才会被回收。
推荐使用的方式是,动态类加载不保存类对象,创建后就释放掉,这样就不会造成内存溢出了(其实这就是JSP加载机制了)。
原文链接:Java类加载相关学习笔记(2),转载请注明来源!