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