TOMCAT學習之類加載器

       Tomcat引入自定義類加載器是基於這幾點考慮:一、servlet不能徹底信任它正在運行的servlet類,因此不能簡單的使用系統類加載器;二、爲了實現類發生變化時自動重載功能。java

       Tomcat在啓動引導類Bootstrap中對類加載器進行了初始化,以方便在後面的運行過程當中加載所須要的類。接下來咱們分析一下Tomcat如何建立類加載器。apache

       一、加載conf目錄下屬性配置文件catalina.properties,分別獲取common.loader、server.loader、shared.loader等屬性對應的值,並進行處理,具體見下面代碼:ide

代碼:this

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


二、接下來咱們看一下ClassLoaderFactory中是如何建立類加載器的:url

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>();
        /**
          * 對倉庫中的資源類型進行判斷,
          * 一、 若是爲URL類型就加入set集合,
          * 二、若是爲其餘類型,則會判斷它是否爲文件,若是是則進行轉換並加入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);
                    }
                });
    }

三、獲得classloader以後,即可以加載須要用到的類了:debug

例1:SecurityClassLoad.securityClassLoad(catalinaLoader);code

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

相關文章
相關標籤/搜索