ClassLoader类getSystemClassLoader()方法源码剖析

1.getSystemClassLoader方法

    private static ClassLoader scl;

    @CallerSensitive
    public static ClassLoader getSystemClassLoader() {
        //初始化系统类加载器
        initSystemClassLoader();
        if (scl == null) {
            return null;
        }
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkClassLoaderPermission(scl, Reflection.getCallerClass());
        }
        return scl;
    }

    private static synchronized void initSystemClassLoader() {
        //scl是一个ClassLoader的对象,代表着系统类加载器,scl全称systenClassLoader
        //已经设置的话就不进行以下操作
        if (!sclSet) {
            //没有进行设置,但是scl != null,这是不应该的所以报错
            if (scl != null)
            /* 
            Launcher类如果是Eclipse的朋友是看不到源码的,可以去看OpenJDK的代码
            以下是Launcher类的代码,它的构造方法是私有的,只能通过getLauncher()得到该类的实例
            
            private ClassLoader loader;这个成员存的是系统类加载器

            private static Launcher launcher = new Launcher();

            public static Launcher getLauncher() {
              return launcher;
            }
            在其私有构造方法中你只需要知道做了三件事,1.创建了扩展类加载器 2.利用扩展类加载器创建了系统类加载器
            3.将系统类加载器作为初始线程的上下文加载器   
            */
            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
            if (l != null) {
                Throwable oops = null;
                //得到系统类加载器
                scl = l.ge
                    //doPrivileged方法十个native方法,它会执行其参数的run方法,
                    //最终我们会得到一个应用类加载器,该应用类加载器可能是系统类加载器,也可是我们自己定义的类加载器
                    scl = AccessController.doPrivileged(
                        new SystemClassLoaderAction(scl));
                } catch (PrivilegedActionException pae) {
                    oops = pae.getCause();
                    if (oops instanceof InvocationTargetException) {
                        oops = oops.getCause();
                    }
                }
                if (oops != null) {
                    if (oops instanceof Error) {
                        throw (Error) oops;
                    } else {
                        // wrap the exception
                        throw new Error(oops);
                    }
                }
            }
            sclSet = true;
        }
    }

    class SystemClassLoaderAction
    implements PrivilegedExceptionAction<ClassLoader> {
    private ClassLoader parent;

    SystemClassLoaderAction(ClassLoader parent) {
        this.parent = parent;
    }

    public ClassLoader run() throws Exception {
        /*
        我们自己写的自定义类加载器也可以作为应用类加载器,只需要进行以下操作,或者在命令行更改
        System.setProperty("java.system.class.loader","自定义类加载器的全权限定名");
        */
        String cls = System.getProperty("java.system.class.loader");
        //如果没有,将该系统类加载器返回即可
        if (cls == null) {
            return parent;
        }
        /*
        如果有我们自己的定义的类加载,要先对它进行类加载会得到一个Class<?>对象,再利用反射机制得到单参数构造方法
        执行该构造方法,这块的目的是将parent作为了自定义类加载器的父加载器。
        并把自定义类加载器设置为当前线程的上下文类加载器

        这块类加载用到了Class.forName(cls, true, parent)方法,稍后我们会进行讲解
        */
        Constructor<?> ctor = Class.forName(cls, true, parent)
            .getDeclaredConstructor(new Class<?>[] { ClassLoader.class });
        ClassLoader sys = (ClassLoader) ctor.newInstance(
            new Object[] { parent });
        Thread.currentThread().setContextClassLoader(sys);
        return sys;
    }
}

forName()方法

对于Class.forName方法,我相信大多数人都是从JDBC连接数据库时了解到的,当时其实没有学过类加载器,所有并不知道这个方法的用意,今天分析一下它的源码。

forName()方法有两种

public static Class<?> forName(String className);
public static Class<?> forName(String name, boolean initialize,ClassLoader loader);

@CallerSensitive
    public static Class<?> forName(String name, boolean initialize,
                                   ClassLoader loader)
        throws ClassNotFoundException
    {
        Class<?> caller = null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            // Reflective call to get caller class is only needed if a security manager
            // is present.  Avoid the overhead of making this call otherwise.
            //getCallerClass()该方法是一个native方法,作用是得到调用这个forName方法的Class<?>对象
            caller = Reflection.getCallerClass();
            if (sun.misc.VM.isSystemDomainLoader(loader)) {
                //得到加载调用者的类加载器
                ClassLoader ccl = ClassLoader.getClassLoader(caller);
                if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                    sm.checkPermission(
                        SecurityConstants.GET_CLASSLOADER_PERMISSION);
                }
            }
        }
        //这是个native方法作用加载名字为name的类,并返回它的Calss<?>对象
        return forName0(name, initialize, loader, caller);
    }

     @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        //得到调用该方法的Class<?>对象
        Class<?> caller = Reflection.getCallerClass();
        //forName0方法是一个native方法,最终会使用加载了调用者类的类加载器来加载className所对应的类
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

总结 forName方法如果没有传入类加载器,会使用最终会使用加载了调用者类的类加载器来加载所对应的类

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值