首先介紹自定義類的應用場景:
(1)加密:Java代碼可以輕易的被反編譯,如果你需要把自己的代碼進行加密以防止反編譯,可以先將編譯後的代碼用某種加密算法加密,類加密後就不能再用Java的ClassLoader去加載類了,這時就需要自定義ClassLoader在加載類的時候先解密類,然後再加載。
(2)從非標準的來源加載代碼:如果你的字節碼是放在數據庫、甚至是在雲端,就可以自定義類加載器,從指定的來源加載類。
(3)以上兩種情況在實際中的綜合運用:比如你的應用需要通過網絡來傳輸 Java 類的字節碼,爲了安全性,這些字節碼經過了加密處理。這個時候你就需要自定義類加載器來從某個網絡地址上讀取加密後的字節代碼,接着進行解密和驗證,最後定義出在Java虛擬機中運行的類。
package com.test6; public class DataInfo { private Long id; private String userName; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } @Override public String toString() { return "DataInfo [id=" + 1 + ", userName=" + "測試" + "]"; } }
package com.test6; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; /** * 自定義加載器 * * @author sdc * */ public class MySelfClassLoader extends ClassLoader { public MySelfClassLoader() { } public MySelfClassLoader(ClassLoader parent) { super(parent); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { File file = new File("D:/DataInfo.class"); try { byte[] bytes = getClassBytes(file); // defineClass方法可以把二進制流字節組成的文件轉換爲一個java.lang.Class Class<?> cla = this.defineClass(name, bytes, 0, bytes.length); return cla; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return super.findClass(name); } private byte[] getClassBytes(File file) throws Exception { // 這裏要讀入.class的字節,因此要使用字節流 FileInputStream fis = new FileInputStream(file); FileChannel fc = fis.getChannel(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); WritableByteChannel wbc = Channels.newChannel(baos); ByteBuffer by = ByteBuffer.allocate(1024); while (true) { int i = fc.read(by); if (i == 0 || i == -1) break; by.flip(); wbc.write(by); by.clear(); } fis.close(); return baos.toByteArray(); } public static void main(String[] args) { MySelfClassLoader mcl = new MySelfClassLoader(); Class<?> clazz; try { clazz = Class.forName("DataInfo", true, mcl); Object obj = clazz.newInstance(); System.out.println(obj); System.out.println(obj.getClass().getClassLoader());// 打印出我們的自定義類加載器 } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }