TOMCAT学习之类加载器

       Tomcat引入自定义类加载器是基于这几点考虑:1、servlet不能完全信任它正在运行的servlet类,所以不能简单的使用系统类加载器;2、为了实现类发生变化时自动重载功能。

       Tomcat在启动引导类Bootstrap中对类加载器进行了初始化,以方便在后面的运行过程中加载所需要的类。接下来我们分析一下Tomcat如何创建类加载器。

       1、加载conf目录下属性配置文件catalina.properties,分别获取common.loader、server.loader、shared.loader等属性对应的值,并进行处理,具体见下面代码:

代码:

private ClassLoader createClassLoader(String name, ClassLoader parent)
        throws Exception {
        //加载conf目录下属性配置文件catalina.properties,
        //分别获取common.loader、server.loader、shared.loader等属性
        String value = CatalinaProperties.getProperty(name + ".loader");  
        if ((value == null) || (value.equals("")))
            return parent;
        //将${catalina.base}/${catalina.home}进行替换
        value = replace(value);
        List<Repository> repositories = new ArrayList<Repository>();
        StringTokenizer tokenizer = new StringTokenizer(value, ",");
        while (tokenizer.hasMoreElements()) {
            String repository = tokenizer.nextToken().trim();
            if (repository.length() == 0) {
                continue;
            }
            // Check for a JAR URL repository
            try {
                @SuppressWarnings("unused")
                URL url = new URL(repository);
                repositories.add(
                        new Repository(repository, RepositoryType.URL));
                continue;
            } catch (MalformedURLException e) {
                // Ignore
            }
            // Local repository
            if (repository.endsWith("*.jar")) {
                repository = repository.substring
                    (0, repository.length() - "*.jar".length());
                repositories.add(
                        new Repository(repository, RepositoryType.GLOB));
            } else if (repository.endsWith(".jar")) {
                repositories.add(
                        new Repository(repository, RepositoryType.JAR));
            } else {
                repositories.add(
                        new Repository(repository, RepositoryType.DIR));
            }
        }
        //用类加载器工厂创建类加载器
        ClassLoader classLoader = ClassLoaderFactory.createClassLoader
            (repositories, parent);
        // Retrieving MBean server
        //下面这部分代码,大家可以参考JMX相关的知识
        MBeanServer mBeanServer = null;
        if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
            mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0);
        } else {
            mBeanServer = ManagementFactory.getPlatformMBeanServer();
        }
        // Register the server classloader
        ObjectName objectName =
            new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
        mBeanServer.registerMBean(classLoader, objectName);
        return classLoader;
    }


2、接下来我们看一下ClassLoaderFactory中是如何创建类加载器的:

public static ClassLoader createClassLoader(List<Repository> repositories,
                                                final ClassLoader parent)
        throws Exception {
        if (log.isDebugEnabled())
            log.debug("Creating new class loader");
        // Construct the "class path" for this class loader
        Set<URL> set = new LinkedHashSet<URL>();
        /**
          * 对仓库中的资源类型进行判断,
          * 1、 如果为URL类型就加入set集合,
          * 2、如果为其他类型,则会判断它是否为文件,如果是则进行转换并加入set集合,否则跳过;
          * 最后创建 StandardClassLoader 对象并返回     
          */
        if (repositories != null) {
            for (Repository repository : repositories)  {
                if (repository.getType() == RepositoryType.URL) {
                    URL url = new URL(repository.getLocation());
                    if (log.isDebugEnabled())
                        log.debug("  Including URL " + url);
                    set.add(url);
                } else if (repository.getType() == RepositoryType.DIR) {
                    File directory = new File(repository.getLocation());
                    directory = directory.getCanonicalFile();
                    if (!validateFile(directory, RepositoryType.DIR)) {
                        continue;
                    }
                    URL url = directory.toURI().toURL();
                    if (log.isDebugEnabled())
                        log.debug("  Including directory " + url);
                    set.add(url);
                } else if (repository.getType() == RepositoryType.JAR) {
                    File file=new File(repository.getLocation());
                    file = file.getCanonicalFile();
                    if (!validateFile(file, RepositoryType.JAR)) {
                        continue;
                    }
                    URL url = file.toURI().toURL();
                    if (log.isDebugEnabled())
                        log.debug("  Including jar file " + url);
                    set.add(url);
                } else if (repository.getType() == RepositoryType.GLOB) {
                    File directory=new File(repository.getLocation());
                    directory = directory.getCanonicalFile();
                    if (!validateFile(directory, RepositoryType.GLOB)) {
                        continue;
                    }
                    if (log.isDebugEnabled())
                        log.debug("  Including directory glob "
                            + directory.getAbsolutePath());
                    String filenames[] = directory.list();
                    for (int j = 0; j < filenames.length; j++) {
                        String filename = filenames[j].toLowerCase(Locale.ENGLISH);
                        if (!filename.endsWith(".jar"))
                            continue;
                        File file = new File(directory, filenames[j]);
                        file = file.getCanonicalFile();
                        if (!validateFile(file, RepositoryType.JAR)) {
                            continue;
                        }
                        if (log.isDebugEnabled())
                            log.debug("    Including glob jar file "
                                + file.getAbsolutePath());
                        URL url = file.toURI().toURL();
                        set.add(url);
                    }
                }
            }
        }
        // Construct the class loader itself
        final URL[] array = set.toArray(new URL[set.size()]);
        if (log.isDebugEnabled())
            for (int i = 0; i < array.length; i++) {
                log.debug("  location " + i + " is " + array[i]);
            }
        //这里AccessController.doPrivileged意思是这个是特别的,不用做权限检查
        return AccessController.doPrivileged(
                new PrivilegedAction<StandardClassLoader>() {
                    @Override
                    public StandardClassLoader run() {
                        if (parent == null)
                            return new StandardClassLoader(array);
                        else
                            return new StandardClassLoader(array, parent);
                    }
                });
    }

3、得到classloader之后,便可以加载需要用到的类了:

例1:SecurityClassLoad.securityClassLoad(catalinaLoader);

例2:Class startupClass =  catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina");


你可能感兴趣的:(tomcat,类加载器)