类加载器的作用:动态加载java class文件到jvm内存中,让jvm能够调用并执行class文件中的字节码
自定义类加载器
1、加载class文件的类加载器
1.1、类
在/Users/indi目录下有一个test.class文件
1.2、类加载器
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyClassLoader extends ClassLoader {
private String root;
public String getRoot() {
return root;
}
public void setRoot(String root) {
this.root = root;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = loadClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
} else {
return defineClass(name, classData, 0, classData.length);
}
}
private byte[] loadClassData(String className) {
String fileName = root + File.separatorChar
+ className.replace('.', File.separatorChar) + ".class";
try {
InputStream ins = new FileInputStream(fileName);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = ins.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
测试
public static void main(String[] args) {
MyClassLoader classLoader = new MyClassLoader();
// root是类所在目录
classLoader.setRoot("/Users/indi");
Class<?> testClass = null;
try {
// test是类名称
testClass = classLoader.loadClass("test");
Object object = testClass.newInstance();
System.out.println(object.getClass().getClassLoader());
Method test = testClass.getMethod("test");
test.invoke(object);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
}
2、加载加密后的class文件的类加载器
2.1、对class文件进行加密
import java.io.*;
/**
* 加密
*/
public class Encrypt {
public static void main(String[] args) {
encrypt(new File("/Users/indi/test.class"),new File("/Users/indi/encrypt/test.class"));
}
/**
* 加密算法
* @param rsource
* @param target
*/
public static void encrypt(File rsource,File target){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(rsource);
fos = new FileOutputStream(target);
int temp = -1;
while ((temp = fis.read()) != -1){
fos.write(temp ^ 0x98);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException ioException){
}finally {
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.2、解密类加载器
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class DecryptClassLoader extends ClassLoader {
private String root;
public DecryptClassLoader(String root){
this.root = root;
}
private static final String CLASS_SUFFIX = ".class";
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = this.loadClassData(name);
if (data == null) {
return super.findClass(name);
}
return super.defineClass(name, data, 0, data.length);
}
public byte[] loadClassData(String className) {
String filePath = getFilePath(className);
ByteArrayOutputStream bos = null;
try {
InputStream is = new FileInputStream(filePath);
bos = new ByteArrayOutputStream();
int temp = -1;
while ((temp = is.read()) != -1) {
bos.write(temp ^ 0x98);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
return bos.toByteArray();
}
}
private String getFilePath(String className) {
return this.root + File.separatorChar + className + CLASS_SUFFIX;
}
}
测试
public static void main(String[] args) {
DecryptClassLoader classLoader = new DecryptClassLoader("/Users/indi/encrypt");
try {
Class<?> clazz = classLoader.findClass("test");
Object obj = clazz.newInstance();
Method method = clazz.getMethod("test");
method.invoke(obj);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
e.printStackTrace();
}
}