posts - 78, comments - 34, trackbacks - 0, articles - 1
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

                          從張老師的基礎(chǔ)增強(qiáng)課上,我就想深入了解一下類(lèi)加載器。然后聽(tīng)懂了張老師的課,知道了JAVA類(lèi)加載的方式,以及實(shí)現(xiàn)自己的類(lèi)加載器的應(yīng)用。但一直沒(méi)有自己去編寫(xiě)類(lèi)加載器,也對(duì)class文件的具體處理方式不了解。今日休息,有時(shí)間深入了解一下。

           

          一、JAVA有三個(gè)類(lèi)加載器:

          1.bootstrap class loader,負(fù)責(zé)加載系統(tǒng)類(lèi),比如jdkrt.jar包里的類(lèi)。

          2.extension class loader,負(fù)責(zé)加載jre/lib/ext目錄下的所有類(lèi)。

          3.system class loader,負(fù)責(zé)加載環(huán)境變量classpath指向目錄下的所有類(lèi)。

           

          他們?nèi)齻€(gè)依次是“父子關(guān)系”,因?yàn)?/span>bootstrap class loader一般是使用C語(yǔ)言編寫(xiě)的,所以用戶(hù)無(wú)法獲取它的對(duì)象。

           

          當(dāng)在classpath環(huán)境變量中的一個(gè)class文件被加載時(shí),system class loader會(huì)將class交給父類(lèi)extension class loader加載,extension class loader會(huì)將class交給bootstrap class loader加載。如果bootstrap class loader加載不了,則返回給extension class loader加載,如果extension class loader加載不了,則返回給system class loader加載。

           

          被其中一個(gè)加載器成功加載后,便解析class文件。如果class文件中有使用到其他類(lèi)對(duì)象,則繼續(xù)調(diào)用類(lèi)加載器加載。

           

          有些情況下不希望被用戶(hù)看到Class文件的明文,比如為了保護(hù)軟件的安全、防止破解等。《JAVA核心技術(shù)第2卷》也有提到編寫(xiě)自己的類(lèi)加載器,實(shí)現(xiàn)加載被加了密的class文件。

           

          下面實(shí)現(xiàn)一個(gè)自己的類(lèi)加載器,加載被加密了的class文件:

           

          EasyTest.java用于被自定義類(lèi)加載器加載。

          public class EasyTest {

                public void print(){

                      System.out.println("EasyTest,you did it!");

                }

          }

           

          Mycipher.java用于加密EasyTest.class

          package cn.itcast.cc.cipher;

           

          import java.io.*;

          import java.security.Key;

          import javax.crypto.*;

           

          public class MyCipher {

                private Key key = null;

                private String traninfo = null;

           

                public MyCipher(Key key, String traninfo) {

                      this.key = key;

                      this.traninfo = traninfo;

                }

           

                public void cipher(InputStream ins, OutputStream ous) throws IOException {

                      // 創(chuàng)建加密輸出流

                      Cipher cip = null;

                      CipherOutputStream cos = null;

                      try {

                            cip = Cipher.getInstance(this.traninfo);

                            cip.init(Cipher.ENCRYPT_MODE, this.key);

                            cos = new CipherOutputStream(ous, cip);

                            // 寫(xiě)出到輸入流

                            int len = 0;

                            byte[] buf = new byte[1024];

                            while ((len = ins.read(buf)) != -1) {

                                  cos.write(buf, 0, len);

                            }

                      } catch (Exception e) {

                            e.printStackTrace();

                      } finally {

                            // 釋放輸入和輸出流

                            cos.close();

                            ins.close();

                            ous.close();

                      }

                }

          }

           

          MyClassLoader.java是自定義類(lèi)加載器,用于解密被加密后的class文件。

          package cn.itcast.cc.classloader;

           

          import java.io.*;

          import java.security.Key;

          import javax.crypto.*;

           

          public class MyClassLoader extends ClassLoader {

                private Key key = null;

                private String traninfo = null;

           

                public MyClassLoader(Key key, String traninfo) {

                      this.key = key;

                      this.traninfo = traninfo;

                }

           

                @Override

                @SuppressWarnings("unchecked")

                protected Class findClass(String name) throws ClassNotFoundException {

                      // 獲取class解密后的字節(jié)碼

                      byte[] classBytes = null;

                      try {

                            classBytes = loadClassBytes(name);

                      } catch (Exception e) {

                            throw new ClassNotFoundException(name);

                      }

                     

                      // 使用字節(jié)碼,實(shí)例類(lèi)對(duì)象

                      String clname = name.substring(name.lastIndexOf("/") + 1, name

                                  .lastIndexOf("."));

                      Class cl = defineClass(clname, classBytes, 0, classBytes.length);

                      if (cl == null)

                            throw new ClassNotFoundException(name);

                      return cl;

                }

           

                private byte[] loadClassBytes(String name) throws IOException {

                      // 讀入文件

                      FileInputStream ins = null;

                      ByteArrayOutputStream baos = null;

                      CipherInputStream cis = null;

                      byte[] result = null;

                      try {

                            ins = new FileInputStream(name);

                            Cipher cip = Cipher.getInstance(this.traninfo);

                            cip.init(Cipher.DECRYPT_MODE, this.key);

                            // 使用密碼解密class文件

                            cis = new CipherInputStream(ins, cip);

                            baos = new ByteArrayOutputStream();

                            int len = 0;

                            byte[] buf = new byte[1024];

                            while ((len = cis.read(buf)) != -1) {

                                  baos.write(buf, 0, len);

                            }

                            result = baos.toByteArray();

                      } catch (Exception e) {

                            e.printStackTrace();

                      } finally {

                            // 釋放流

                            baos.close();

                            cis.close();

                            ins.close();

                      }

           

                      return result;

                }

          }

           

          Test.java,用于測(cè)試自定義類(lèi)加載器。

          package cn.itcast.cc.testcalss;

           

          import java.io.*;

          import java.lang.reflect.Method;

          import java.security.Key;

          import javax.crypto.KeyGenerator;

          import cn.itcast.cc.cipher.MyCipher;

          import cn.itcast.cc.classloader.MyClassLoader;

           

          public class Test {

                public static void main(String[] args) {

                      KeyGenerator keyGen;

                      try {

                            // 創(chuàng)建密鑰

                            keyGen = KeyGenerator.getInstance("AES");

                            keyGen.init(128);

                            Key key = keyGen.generateKey();

                            keyGen = null;

           

                            MyCipher mc = new MyCipher(key,"AES/ECB/PKCS5Padding");

                            mc.cipher(new FileInputStream(new File("C:/EasyTestbak.class")),

                                        new FileOutputStream(new File("C:/EasyTest.class")));

           

                            MyClassLoader mcl = new MyClassLoader(key,"AES/ECB/PKCS5Padding");

                           

                            Class clazz = mcl.loadClass("C:/EasyTest.class");

                            Method meth = clazz.getMethod("print", null);

                            meth.invoke(clazz.newInstance(), null);

           

                      } catch (Exception e1) {

                            e1.printStackTrace();

                      }

                }

          }

           

          注意:將EasyTest.java編譯后放到C盤(pán):C:/EasyTestbak.class

           

          例子寫(xiě)的不干凈,主要是為了演示自定義類(lèi)加載器!

           

                      學(xué)習(xí)了tomcat servlet以來(lái)便對(duì)它們的實(shí)現(xiàn)機(jī)制比較感興趣,雖然已經(jīng)弄懂了他們簡(jiǎn)單的實(shí)現(xiàn)原理。但今日看到《實(shí)現(xiàn)自己的類(lèi)加載器》這篇文章時(shí),讓對(duì)有了更深入的了解。在tomcatwebapps目錄下的所有WEB應(yīng)用中的class文件和jar文件,都是在Tomcat啟動(dòng)時(shí)將全路徑記錄到URLClassloader中。需要什么類(lèi),直接調(diào)用URLClassloader.loaderclass()方法即可!

           

                      我原本想自己找到class文件的全路徑,然后調(diào)用class.forname的方法不也可以嗎?但如果有JAR包,我還需要使用JARInputstream讀入,然后再搜索嗎?這樣太麻煩,所以還是使用URLClassloader比較好,它全處理了。

           

                      它的實(shí)現(xiàn)原理,請(qǐng)看《實(shí)現(xiàn)自己的類(lèi)加載器》 http://ajava.org/course/java/14990.html

           

           

          參考文獻(xiàn):《實(shí)現(xiàn)自己的類(lèi)加載器》 http://ajava.org/course/java/14990.html


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 元阳县| 佛冈县| 亳州市| 静乐县| 西青区| 雷州市| 枣强县| 涞源县| 上饶市| 桂阳县| 玉林市| 慈利县| 莆田市| 乌兰浩特市| 昌江| 泸州市| 滕州市| 通州市| 龙胜| 阳信县| 牙克石市| 周口市| 调兵山市| 宜川县| 福州市| 年辖:市辖区| 开远市| 梅河口市| 开封县| 宝鸡市| 城市| 泉州市| 吴桥县| 内江市| 延安市| 长武县| 织金县| 德格县| 梅州市| 宝丰县| 镇江市|