轉載ClassLoader類加載器
類加載器負責將 .class 文件(可能在磁盤上, 也可能在網絡上) 加載到內存中, 并為之生成對應的 java.lang.Class 對象
當 JVM 啟動時,會形成由三個類加載器組成的初始類加載器層次結構:

bootstrap classloader:引導(也稱為原始)類加載器,它負責加載Java的核心類。這個加載器的是非常特殊的,它實際上不是 java.lang.ClassLoader的子類,而是由JVM自身實現的。可以通過執行以下代碼來獲得bootstrap classloader加載了那些核心類庫:
- URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
- for (int i = 0; i < urls.length; i++) {
- System.out.println(urls[i].toExternalForm());
- }
因為JVM在啟動的時候就自動加載它們,所以不需要在系統屬性CLASSPATH中指定這些類庫
extension classloader -擴展類加載器,它負責加載JRE的擴展目錄(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系統屬性指定的)中的JAR包。這為引入除Java核心類以外的新功能提供了一個標準機制。因為默認的擴展目錄對所有從同一個JRE中啟動的JVM都是通用的,所以放入這個目錄的 JAR類包對所有的JVM和system classloader都是可見的。
system classloader - 系統(也稱為應用)類加載器,它負責在JVM被啟動時,加載來自在命令java中的-classpath或者java.class.path系統屬性或者CLASSPATH操作系統屬性所指定的JAR類包和類路徑。
可以通過靜態方法ClassLoader.getSystemClassLoader()找到該類加載器。如果沒有特別指定,則用戶自定義的任何類加載器都將該類加載器作為它的父加載器。
classloader 加載類用的是全盤負責和委托機制。
全盤負責:即是當一個classloader加載一個Class的時候,這個Class所依賴的和引用的其它Class通常也由這個classloader負責載入。
委托機制:先讓parent(父)類加載器 尋找,只有在parent找不到的時候才從自己的類路徑中去尋找。
類加載還采用了cache機制:如果 cache中保存了這個Class就直接返回它,如果沒有才從文件中讀取和轉換成Class,并存入cache,這就是為什么修改了Class但是必須重新啟動JVM才能生效,并且類只加載一次的原因。
給一個class文件進行簡單的加密,加密后人家對其反編譯,也獲取不了我們的源代碼
寫一個簡單需要加密的類,這里繼承一個Date,為什么要繼續一個父類。因為后面需要解密的class已經被打亂了,所以在解密的時候你需要反射然后強行轉換class的時候也是強行轉換為一個被加密的class這是會出錯,但是你繼承了一個父類后你就可以強行轉換為一個父類這樣子就不會有錯誤了
- <span style="font-size:16px;">public class ClassLoaderAttachment extends Date {
- public String toString(){
- return "baby goodnight";
- }
- }</span>
分別InputStream 指定了需要加密的文件 ,OutputStream加密后輸出的文件
- <span style="font-size:16px;"> private static void cypher(InputStream ips ,OutputStream ops) throws Exception{
- int b = -1;
- while((b=ips.read())!=-1){
- ops.write(b ^ 0xff);
- }
- }</span>
加密后給這個class人家使用的時候是沒法使用的,會出現Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 這樣子的異常除非人家知道你的解密方法 將轉換為正確的class ,另外一個方法是通過extends ClassLoader 覆寫findClass(String name)的方法來實現 自定義一個classLoader 然后通過我們的classloader去使用這個文件
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- // TODO Auto-generated method stub
- String classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.')+1) + ".class";
- try {
- FileInputStream fis = new FileInputStream(classFileName);
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- cypher(fis,bos);//對其進行解密
- fis.close();
- System.out.println("aaa");
- byte[] bytes = bos.toByteArray();
- return defineClass(bytes, 0, bytes.length);
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
使用自定義的ClassLoader使用加密的class可能會出現的異常,父類的加載器會去找原來工程的class 并不是找我們指定的class,把原來工程的class移除掉
第二個可能出現的是 之前在編譯的時候 內存中已經保留了原來的jar文件,把eclipse關閉后清空內存在執行
類加載器補充:
在servlet中的時候無法加載httpServlet 把httpServlet 的jar包放到ExtClassLoader管理的目錄下就可以了

原因是這個樣子的 當由ExtClassLoader加載MyServlet的時候先交給他的父類去加載是可以加載成功的時候,MyServlet還需要加載HttpServlet 此時ExtClassLoader的父類沒有加載成功于是就由ExtClassLoader加載,加載失敗后不會交個WebAppClassLoader加載,所以在用ExtClassLoader加載HttpServlet卻沒法加載成功!
本文由用戶 chyx413332087 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!