1. 程式人生 > >Java原始碼解析(7) —— ClassLoader(2)

Java原始碼解析(7) —— ClassLoader(2)

ClassLoader原始碼解析續
這一部分是ClassLoader核心部分,載入給定的資料成對應的類物件。

/**
 * 由虛擬機器呼叫,這是一個private方法,但我在ClassLoader原始碼中並未看到有地方呼叫
 * 看名字及原始碼說明,是由虛擬機器載入類的時候內部呼叫,百度查詢估計是載入jdk類時
 * 系統類載入器通過反射呼叫該方法(jdk類中有許多類似用法)
 */
    private Class loadClassInternal(String name)
        throws ClassNotFoundException
    {
        if (parallelLockMap == null
) { synchronized (this) { return loadClass(name); } } else { return loadClass(name); } } // 根據安全域策略,檢查包許可權,同樣,由虛擬機器在載入一個類後呼叫 private void checkPackageAccess(Class cls, ProtectionDomain pd) { final SecurityManager sm = System.getSecurityManager(); //如果存在安全管理器
if (sm != null) { if (ReflectUtil.isNonPublicProxyClass(cls)) { //代理類的走這邊,迴圈該類所實現的介面,對其進行相應的包許可權校驗 for (Class intf: cls.getInterfaces()) { checkPackageAccess(intf, pd); } return; } final
String name = cls.getName(); final int i = name.lastIndexOf('.'); if (i != -1) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { //具體的實現,由SecurityManager的native方法實現 sm.checkPackageAccess(name.substring(0, i)); return null; } }, new AccessControlContext(new ProtectionDomain[] {pd})); } } domains.add(pd); } /** * 類載入真正實現方法,由子類自己實現 * 一般真正實現會呼叫下方defineClass()相關方法 */ protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); } /** * 將位元組陣列轉化為Class物件 * 已不推薦使用,其實現中的name=null,會直接丟擲異常 * 由下方defineClass(String, byte[], int, int)代替 * @see #loadClass(String, boolean) * @see #resolveClass(Class) */ @Deprecated protected final Class<?> defineClass(byte[] b, int off, int len) throws ClassFormatError { return defineClass(null, b, off, len, null); } /** * 位元組流轉化為Java Class物件,也可以理解為將位元組流轉換成JVM位元組碼 * name是表示將對應的位元組流轉化為對應路徑類名的類的JVM位元組碼 * * 這其中涉及到了安全策略、保護域、許可權等知識。 * * @see #loadClass(String, boolean) * @see #resolveClass(Class) * @see java.security.CodeSource * @see java.security.SecureClassLoader */ protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError { //底層實現,檢視下方對應方法 return defineClass(name, b, off, len, null); } /** * 決定類對應的保護域 * name是類的全路徑名 */ private ProtectionDomain preDefineClass(String name, ProtectionDomain pd) { //類名格式是否合法 if (!checkName(name)) throw new NoClassDefFoundError("IllegalName: " + name); //java開頭的包為系統類,無權更改 if ((name != null) && name.startsWith("java.")) { throw new SecurityException ("Prohibited package name: " + name.substring(0, name.lastIndexOf('.'))); } if (pd == null) { pd = defaultDomain; } //檢查簽名 if (name != null) checkCerts(name, pd.getCodeSource()); return pd; } private String defineClassSourceLocation(ProtectionDomain pd) { CodeSource cs = pd.getCodeSource(); String source = null; if (cs != null && cs.getLocation() != null) { source = cs.getLocation().toString(); } return source; } //這個方法作用:當類載入錯誤(位元組資料格式錯誤等),嘗試重新定義類(重新生成Class物件) private Class defineTransformedClass(String name, byte[] b, int off, int len, ProtectionDomain pd, ClassFormatError cfe, String source) throws ClassFormatError { ClassFileTransformer[] transformers = ClassFileTransformer.getTransformers(); Class c = null; if (transformers != null) { for (ClassFileTransformer transformer : transformers) { try { //使用對應的轉換器將對應位元組流轉換成相應(編碼?)的位元組流 //可能是對特定格式的位元組流的處理? byte[] tb = transformer.transform(b, off, len); c = defineClass1(name, tb, 0, tb.length, pd, source); break; } catch (ClassFormatError cfe2) { // 該轉換器無效,嘗試下一個 } } } // 最終失敗,丟擲異常 if (c == null) throw cfe; return c; } //給類設定簽名,呼叫本地方法 private void postDefineClass(Class c, ProtectionDomain pd) { if (pd.getCodeSource() != null) { Certificate certs[] = pd.getCodeSource().getCertificates(); if (certs != null) setSigners(c, certs); } } /** * 載入對應類名Class */ protected final Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) throws ClassFormatError { //檢查ClassLoader是否被初始化,未初始化丟擲未初始化異常 //另外,設定相應保護域 protectionDomain = preDefineClass(name, protectionDomain); Class c = null; String source = defineClassSourceLocation(protectionDomain); try { //呼叫native方法生成class檔案,native方法的具體實現與JVM相關 c = defineClass1(name, b, off, len, protectionDomain, source); } catch (ClassFormatError cfe) { //出錯,嘗試使用特定轉換器,重新載入 c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source); } //設定簽名 postDefineClass(c, protectionDomain); return c; } /** * 載入緩衝區型別資料的類 * 類似上方方法,只是Class資料來源不同 */ protected final Class<?> defineClass(String name, java.nio.ByteBuffer b, ProtectionDomain protectionDomain) throws ClassFormatError { int len = b.remaining(); // 虛擬機器記憶體,使用byte[]方式載入,即呼叫上方方法 if (!b.isDirect()) { if (b.hasArray()) { return defineClass(name, b.array(), b.position() + b.arrayOffset(), len, protectionDomain); } else { // 無資料格式,或只讀,需要將資料複製到另一塊區域內操作 byte[] tb = new byte[len]; b.get(tb); return defineClass(name, tb, 0, len, protectionDomain); } } //系統記憶體,載入方法 protectionDomain = preDefineClass(name, protectionDomain); Class c = null; String source = defineClassSourceLocation(protectionDomain); try { c = defineClass2(name, b, b.position(), len, protectionDomain, source); } catch (ClassFormatError cfe) { byte[] tb = new byte[len]; b.get(tb); c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe, source); } postDefineClass(c, protectionDomain); return c; } //本地方法,載入類 private native Class defineClass0(String name, byte[] b, int off, int len, ProtectionDomain pd); private native Class defineClass1(String name, byte[] b, int off, int len, ProtectionDomain pd, String source); private native Class defineClass2(String name, java.nio.ByteBuffer b, int off, int len, ProtectionDomain pd, String source); // 校驗類名 private boolean checkName(String name) { if ((name == null) || (name.length() == 0)) return true; if ((name.indexOf('/') != -1) || (!VM.allowArraySyntax() && (name.charAt(0) == '['))) return false; return true; }