并行类加载与OSGI类加载(3)

/**
    * Encapsulates the set of parallel capable loader types.
    */
    private static class ParallelLoaders {
        private ParallelLoaders() {}

// the set of parallel capable loader types
        private static final Set<Class<? extends ClassLoader>> loaderTypes =
            Collections.newSetFromMap(
                new WeakHashMap<Class<? extends ClassLoader>, Boolean>());
        static {
            synchronized (loaderTypes) { loaderTypes.add(ClassLoader.class); }
        }

/**
        * Registers the given class loader type as parallel capabale.
        * Returns {@code true} is successfully registered; {@code false} if
        * loader's super class is not registered.
        */
        static boolean register(Class<? extends ClassLoader> c) {
            synchronized (loaderTypes) {
                if (loaderTypes.contains(c.getSuperclass())) {
                    // register the class loader as parallel capable
                    // if and only if all of its super classes are.
                    // Note: given current classloading sequence, if
                    // the immediate super class is parallel capable,
                    // all the super classes higher up must be too.
                    loaderTypes.add(c);
                    return true;
                } else {
                    return false;
                }
            }
        }

/**
        * Returns {@code true} if the given class loader type is
        * registered as parallel capable.
        */
        static boolean isRegistered(Class<? extends ClassLoader> c) {
            synchronized (loaderTypes) {
                return loaderTypes.contains(c);
            }
        }
    }

原来,一个类加载器想要成为一个并行类加载器,是需要自己注册的,看看注册方法

@CallerSensitive
    protected static boolean registerAsParallelCapable() {
        Class<? extends ClassLoader> callerClass =
            Reflection.getCallerClass().asSubclass(ClassLoader.class);
        return ParallelLoaders.register(callerClass);
    }

最终还是调用了内部类的注册方法。源码在上面,可以看到,一个类加载器要想注册,它的父类必须已经注册了,也就是说从继承路径上的所有父类都必须是并行类加载器。而且一开始,就把ClassLoader这个类注册进去了。

我有个疑问,这里有父类的什么事呢,光注册自己这个类就好了呀。想了半天,还是不明白,是有关于安全吗?哎,大牛就是大牛,哈哈。读者如有明白的,请直言相告。

最后,来看看并行类加载在Tomcat上的应用。原本WebappClassLoader没有注册,只能串行加载类。后来,是阿里意识到了这个问题,解决方案被Tomcat采纳。

static {
        // Register this base class loader as parallel capable on Java 7+ JREs
        Method getClassLoadingLockMethod = null;
        try {
            if (JreCompat.isJre7Available()) {
                final Method registerParallel =
                        ClassLoader.class.getDeclaredMethod("registerAsParallelCapable");
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    @Override
                    public Void run() {
                        registerParallel.setAccessible(true);
                        return null;
                    }
                });
                registerParallel.invoke(null);
                getClassLoadingLockMethod =
                        ClassLoader.class.getDeclaredMethod("getClassLoadingLock", String.class);
            }
        } catch (Exception e) {
            // ignore
        }

这段代码出现在WebappClassLoader类的父类WebappClassLoaderBase里,通过反射调用了ClassLoader类的注册方法。

类的加载能够并行后,我们启动应用的时候,肯定会更快。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/617343b49ea1049d082555572049a935.html