1.基礎使用ClassLoader
1.1 建立自定義ClassLoader并繼承ClassLoader
這裡我隻覆寫了一個findClass方法(實際上可以覆寫更多方法)因為在下文我需要達到加密class,需要覆寫該findClass(),在該findClass裡,調用了我自己寫的一個method:getClassByte(),該方法的作用是讀取class檔案位元組流,那麼我們的加密手段,可以在該方法中做文章哈。當classData為空的時候,我們就交給super的方法處理(抛出ClassNotFound的異常),當classData不為空,那麼我們就加載該類。
import java.io.*;
public class MyClassLoader extends ClassLoader {
private String classPath;
private final static int BUFSIZE = 4096;
public MyClassLoader(String classPath){
this.classPath = classPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException{
try{
byte[] classData = getClassByte(name);
if(classData!=null){
return defineClass(name,classData,0,classData.length);
}
}catch (IOException e){
e.printStackTrace();
}
return super.findClass(name);
}
/***
* class位元組流擷取
*/
private byte[] getClassByte(String className) throws IOException{
String classRealPath = classPath + File.separatorChar + className.replace('.',File.separatorChar)+".class";
byte[] buf = new byte[BUFSIZE];
int len;
ByteArrayOutputStream out = null;
try(InputStream in = new FileInputStream(classRealPath);){
out = new ByteArrayOutputStream();
while ((len = in.read(buf))!=-1){
out.write(buf,0,len);
}
}catch (FileNotFoundException ex){
ex.printStackTrace();
}finally {
if(out!=null){
out.close();
}
}
if(out!=null){
return out.toByteArray();
}
return null;
}
}
2.ClassLoader測試
測試主類中,使用該類加載器進行加載我已經預先編譯好的class檔案,該檔案不要存在運作項目之下,會導緻系統加載器加載該檔案,測試主類:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyClassLoaderTest {
public static void main(String []args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
//自定義類加載器的加載路徑
MyClassLoader myClassLoader=new MyClassLoader("C:\\testcl");
//包名+類名
Class c=myClassLoader.loadClass("MyClassLoaderTestClass");
if(c!=null){
Object obj=c.newInstance();
Method method=c.getMethod("test", null);
method.invoke(obj, null);
System.out.println(c.getClassLoader().toString());
}
}
}
可以看出MyClassLoader已經生效了,運作結果如下:
This is success
classload.MyClassLoader@12bb4df8
3. ClassLoader改造Secuity ClassLoader
3.1 加密解密類
這裡隻編寫單位元組的加密,是以一次讀取一個位元組,而後異或一個數作為加密。
import java.io.*;
public class EncrypClassFile {
public static void encrypt(String src, String dest) throws IOException {
try(InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);) {
int c = -1;
while ((c = in.read()) != -1) {
// 進行單位元組加密
out.write(encryptAlgorithm(c));
}
} catch (Exception e) {
e.printStackTrace();
}
}
/***
* 單位元組加密算法
*/
public static int encryptAlgorithm(int c){
return c ^ 0xff;
}
/***
* 單位元組解密算法
*/
public static int decryptAlgorithm(int c){
return c ^ 0xff;
}
public static void main(String[] args) throws IOException {
encrypt("C:\\testcl\\MyClassLoaderTestClass.class"
,"C:\\testcl\\MyClassLoaderTestClass.eclass");
}
}
3.2 ClassLoader類改造
主要改造的是:getClassByte(),從每次擷取BUFSIZE大小的數組變成每次擷取單位元組,而後進行解密,拼接的檔案字尾,由于加密檔案為eclass,是以這裡也需要變成eclass。
import java.io.*;
public class MyClassLoader extends ClassLoader {
private String classPath;
private final static int BUFSIZE = 4096;
public MyClassLoader(String classPath){
this.classPath = classPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException{
try{
byte[] classData = getClassByte(name);
if(classData!=null){
return defineClass(name,classData,0,classData.length);
}
}catch (IOException e){
e.printStackTrace();
}
return super.findClass(name);
}
/***
* class位元組流擷取
*/
private byte[] getClassByte(String className) throws IOException{
String classRealPath = classPath + File.separatorChar + className.replace('.',File.separatorChar)+".eclass";
byte[] buf = new byte[BUFSIZE];
int c;
ByteArrayOutputStream out = null;
try(InputStream in = new FileInputStream(classRealPath);){
out = new ByteArrayOutputStream();
while ((c = in.read())!=-1){
out.write(EncrypClassFile.decryptAlgorithm(c));
}
}catch (FileNotFoundException ex){
ex.printStackTrace();
}finally {
if(out!=null){
out.close();
}
}
if(out!=null){
return out.toByteArray();
}
return null;
}
}
3.3 測試效果
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyClassLoaderTest {
public static void main(String []args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
//自定義類加載器的加載路徑
MyClassLoader myClassLoader=new MyClassLoader("C:\\testcl");
//包名+類名
Class c=myClassLoader.loadClass("MyClassLoaderTestClass");
if(c!=null){
Object obj=c.newInstance();
Method method=c.getMethod("test", null);
method.invoke(obj, null);
System.out.println(c.getClassLoader().toString());
}
}
}
運作結果:
This is success
classload.MyClassLoader@12bb4df8