日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 类加载器 解密_JAVA类加载器总结整理

發布時間:2024/4/13 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 类加载器 解密_JAVA类加载器总结整理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、What(是什么?)

1、概念

Java類加載器是Java運行時環境的一部分,負責動態加載Java類到JVM的內存空間中。每個Java類必須由某個類加載器裝入到內存中。每一個類加載器都有一個父類加載器(BootStrap引導類加載器沒有)。

2、 JVM中有3個默認的加載器:

(1) BootStrap:引導類加載器。這個加載器很特殊,它不是JAVA類,因此它不需要被別人加載,它嵌套在JVM內核里,也就是說JVM啟動的時候BootStrap就啟動了,它是C++寫的二進制代碼,可以加載別的類。這也是為什么System.class.getClassLoader()結果為null的原因,因為它不是JAVA類,所以它的引用返回null。負責加載核心Java庫,存儲在/jre/lib/rt.jar

(2) ExtClassLoader:擴展類加載器。

(3) AppClassLoader:根據類路徑來加載java類。一般我們自定義的類都是通過這個AppClassLoader加載。

3、類加載器及其委托機制

(1) 當Java虛擬機加載一個類時,如何加載呢?

首先當前線程的類加載器去加載線程中的第一個類(如類A):

l 如果類A引用了類B,Java虛擬機將加載類A的加載器去加載類B

l 還可以直接調用ClassLoader.loadClass()方法來指定某個類加載器去加載某個類

(2) 委托機制的作用—防止內存中出現多分同樣的字節碼

例如類A和類B都要加載System類:

l 如果不用委托機制,都是自己加載,那么類A會加載一份Sysem字節碼,同時類B也會加載一份字節碼看,這樣內存中就出現了兩份System字節碼。

l 如果使用委托機制,會遞歸地向父類查找,首選用BootStrap嘗試加載,如果找不到就向下。這里System就能在BootStrap中找到然后加載。如果此時B也加載System,也從BootStrap,此時BootStrap發現已經加載過System字節碼,則直接返回內存中的System字節碼而不是重新加載,這樣就保證了內存中只有一份字節碼。

例如:用戶使用一個自定義的類(沒有使用自定義類加載器),那么系統就開始從AppClassLoader向父類加載器發送請求,一直到BootStrap,然后BootStrap類加載器沒有父類,于是就開始查找對應路徑下是否有符合要求的類。如果沒有,則又向下查詢,最終回到AppClassLoader(請求的發起者),如果有則返回,沒有則會拋出ClassNotFoundException的異常。如果在AppClassLoader之前,其他類加載器已經找到,則由對應的類加載其返回。

代碼實例1:

public class ClassLoaderTest {

public static void main(String[] args) {

System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());

System.out.println("=========================================");

ClassLoader loader = ClassLoaderTest.class.getClassLoader();

while(loader != null) {

System.out.println(loader.getClass().getName());

loader = loader.getParent();

}

System.out.println(loader);

}

}

代碼實例2:

首先我們自定義一個類:

public class Secret{

public String key(){

return "The key is 5132561";

}

}

然后打印加載這個類的類加載器:

System.out.println(new Secret().getClass().getClassLoader().getClass().getName());

輸出結果如下:

因為從BootStrapèExtClassLoaderèAppClassLoader這個過程中,只有到AppClassLoader才找到對應的類,所以打印AppClassLoader。

代碼實例3:

如果我們將Secret的字節碼打成jar包并放到ExtClassLoader所指向的目錄–/jre/lib/ext目錄下,那么BootStrapèExtClassLoader,到ExtClassLoader就找到了對應的類并返回,這時就打印ExtClassLoader。

打包成jar包并保存到/jre/lib/ext目錄下。

再次輸出:

System.out.println(new Secret().getClass().getClassLoader().getClass().getName());

二、How(如何自定義類加載器?)

自定義的類加載器必須繼承ClassLoader,并實現重載findClass方法。

代碼實例:

public class DecodeClassLoader extends ClassLoader{

private String classDir;

public DecodeClassLoader(){}

public DecodeClassLoader(String classDir){

this.classDir = classDir;

}

@Override

protected Class> findClass(String name) {

File f = new File(classDir,name.substring(name.lastIndexOf(".") + 1) + ".class");

try {

InputStream in = new FileInputStream(f);

ByteArrayOutputStream out = new ByteArrayOutputStream();

encode(in, out);

byte[] bytes = out.toByteArray();

in.close();

out.close();

return defineClass(bytes, 0, bytes.length);

} catch (FileNotFoundException e) {

e.printStackTrace();

}catch (IOException e) {

e.printStackTrace();

}

return null;

}

private static void encode(InputStream in, OutputStream out) throws IOException{

int b = 0;

while((b=in.read())!= -1){

out.write(b ^ 0xff);

}

}

}

三、Where(在什么地方使用?)

(1)運行時裝載或卸載類。常用于:實現腳本語言

用于bean生成器

允許用戶定義的擴展性

允許命名控件之間的通信。

(2)改變Java字節碼的裝入,例如Java類字節碼的加密

(3)修改以裝入的字節碼

四、類加載器的綜合應用實例

通過一個加密類對一個重要的類字節碼進行加密,使得只有使用解密類加載器才可以成功加載并使用。示意圖如下:

(1)DecodeClassLoader.java見上面。

(2)加密類:對Secret字節碼進行加密

public class EncodeUtil {

private static void encode(InputStream in, OutputStream out) throws IOException{

int b = 0;

while((b=in.read())!= -1){

out.write(b ^ 0xff);

}

}

public static void main(String[] args) throws IOException {

String srcPath = "E:\\java_workspace\\004ClassLoaderDemo\\bin\\com\\shuwoom\\classloader\\Secret.class";//args[0];

String destDir = "shuwoomlib";

FileInputStream in = new FileInputStream(srcPath);

String destFileName = srcPath.substring(srcPath.lastIndexOf("\\") + 1);

String destPath = destDir + "\\" + destFileName;

System.out.println(destPath);

FileOutputStream out = new FileOutputStream(destPath);

encode(in,out);

in.close();

out.close();

}

}

(3)被加載的類:

public class Secret{

public String key(){

return "The key is 5132561";

}

}

首先運行EncodeUtil加密工具類,將Secret.class文件加密并保存到指定的shuwoomlib目錄下,此時,在bin/bom/shuwoom/classloader目錄下的Secret是未經加密的字節碼。現在我們將shuwoomlib目錄下加密的Secret.class替換掉bin/bom/shuwoom/classloader目錄下的Secret.class。那么AppClassLoader找到的就是經過加密的字節碼。

//如果直接使用AppClassLoader加載,會報錯。

System.out.println(new Secret().key());

編譯運行會報錯:

//通過DecodeClassLoader類加載器獲得Secret原字節碼

ClassLoader classLoader = new DecodeClassLoader("shuwoomlib");

Class clazz = classLoader.loadClass("Secret");

Method getKeyMethod = clazz.getMethod("key");

System.out.println(getKeyMethod.invoke(clazz.newInstance(), null));

此時才能正常使用。

總結

以上是生活随笔為你收集整理的java 类加载器 解密_JAVA类加载器总结整理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。