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;
    }

猜你喜欢

转载自blog.csdn.net/a327369238/article/details/79173839
今日推荐