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