一、前言
对于apache-tomcat的应用服务器项目应用基于其tomcat-util包中实现web项目/WEB-INF/lib/依赖包加载解析,主要实现功能是org.apache.tomcat.util.scan包路径下,主要涉及代码有org.apache.tomcat.util.scan.StandardJarScanner、org.apache.tomcat.util.scan.Jar、org.apache.tomcat.JarScanner等
二、源码说明
1.org.apache.tomcat.util.scan.Constants配置
package org.apache.tomcat.util.scan;@b@@b@public final class Constants@b@{@b@ public static final String Package = "org.apache.tomcat.util.scan";@b@ public static final String SKIP_JARS_PROPERTY = "tomcat.util.scan.DefaultJarScanner.jarsToSkip";@b@ public static final String JAR_EXT = ".jar";@b@ public static final String WEB_INF_LIB = "/WEB-INF/lib/";@b@ public static final String MERGED_WEB_XML = "org.apache.tomcat.util.scan.MergedWebXml";@b@}
2.org.apache.tomcat.JarScanner接口
package org.apache.tomcat;@b@@b@import java.util.Set;@b@import javax.servlet.ServletContext;@b@@b@public abstract interface JarScanner@b@{@b@ public abstract void scan(ServletContext paramServletContext, ClassLoader paramClassLoader, JarScannerCallback paramJarScannerCallback, Set<String> paramSet);@b@}
3.标准接口实现类StandardJarScanner
package org.apache.tomcat.util.scan;@b@@b@import java.io.File;@b@import java.io.IOException;@b@import java.net.JarURLConnection;@b@import java.net.URI;@b@import java.net.URISyntaxException;@b@import java.net.URL;@b@import java.net.URLClassLoader;@b@import java.net.URLConnection;@b@import java.util.HashSet;@b@import java.util.Iterator;@b@import java.util.Set;@b@import java.util.StringTokenizer;@b@import javax.servlet.ServletContext;@b@import org.apache.juli.logging.Log;@b@import org.apache.juli.logging.LogFactory;@b@import org.apache.tomcat.JarScanner;@b@import org.apache.tomcat.JarScannerCallback;@b@import org.apache.tomcat.util.file.Matcher;@b@import org.apache.tomcat.util.res.StringManager;@b@@b@public class StandardJarScanner@b@ implements JarScanner@b@{@b@ private static final Log log = LogFactory.getLog(StandardJarScanner.class);@b@ private static final Set<String> defaultJarsToSkip = new HashSet();@b@ private static final StringManager sm = StringManager.getManager("org.apache.tomcat.util.scan");@b@ private boolean scanClassPath;@b@ private boolean scanAllFiles;@b@ private boolean scanAllDirectories;@b@ private boolean scanBootstrapClassPath;@b@@b@ public StandardJarScanner()@b@ {@b@ this.scanClassPath = true;@b@@b@ this.scanAllFiles = false;@b@@b@ this.scanAllDirectories = false;@b@@b@ this.scanBootstrapClassPath = false;@b@ }@b@@b@ public boolean isScanClassPath()@b@ {@b@ return this.scanClassPath; }@b@@b@ public void setScanClassPath(boolean scanClassPath) {@b@ this.scanClassPath = scanClassPath;@b@ }@b@@b@ public boolean isScanAllFiles()@b@ {@b@ return this.scanAllFiles; }@b@@b@ public void setScanAllFiles(boolean scanAllFiles) {@b@ this.scanAllFiles = scanAllFiles;@b@ }@b@@b@ public boolean isScanAllDirectories()@b@ {@b@ return this.scanAllDirectories; }@b@@b@ public void setScanAllDirectories(boolean scanAllDirectories) {@b@ this.scanAllDirectories = scanAllDirectories;@b@ }@b@@b@ public boolean isScanBootstrapClassPath()@b@ {@b@ return this.scanBootstrapClassPath; }@b@@b@ public void setScanBootstrapClassPath(boolean scanBootstrapClassPath) {@b@ this.scanBootstrapClassPath = scanBootstrapClassPath;@b@ }@b@@b@ public void scan(ServletContext context, ClassLoader classloader, JarScannerCallback callback, Set<String> jarsToSkip)@b@ {@b@ Set ignoredJars;@b@ if (log.isTraceEnabled()) {@b@ log.trace(sm.getString("jarScan.webinflibStart"));@b@ }@b@@b@ if (jarsToSkip == null)@b@ ignoredJars = defaultJarsToSkip;@b@ else {@b@ ignoredJars = jarsToSkip;@b@ }@b@@b@ Set dirList = context.getResourcePaths("/WEB-INF/lib/");@b@ if (dirList != null) {@b@ Iterator it = dirList.iterator();@b@ while (it.hasNext()) {@b@ String path = (String)it.next();@b@ if ((path.endsWith(".jar")) && (!(Matcher.matchName(ignoredJars, path.substring(path.lastIndexOf(47) + 1)))))@b@ {@b@ if (log.isDebugEnabled())@b@ log.debug(sm.getString("jarScan.webinflibJarScan", new Object[] { path }));@b@@b@ URL url = null;@b@ try@b@ {@b@ String realPath = context.getRealPath(path);@b@ if (realPath == null)@b@ url = context.getResource(path);@b@ else@b@ url = new File(realPath).toURI().toURL();@b@@b@ process(callback, url);@b@ } catch (IOException e) {@b@ log.warn(sm.getString("jarScan.webinflibFail", new Object[] { url }), e);@b@ }@b@ }@b@ else if (log.isTraceEnabled()) {@b@ log.trace(sm.getString("jarScan.webinflibJarNoScan", new Object[] { path }));@b@ }@b@@b@ }@b@@b@ }@b@@b@ if ((this.scanClassPath) && (classloader != null)) {@b@ if (log.isTraceEnabled()) {@b@ log.trace(sm.getString("jarScan.classloaderStart"));@b@ }@b@@b@ ClassLoader loader = classloader;@b@@b@ ClassLoader stopLoader = null;@b@ if (!(this.scanBootstrapClassPath))@b@ {@b@ stopLoader = ClassLoader.getSystemClassLoader().getParent();@b@ }@b@@b@ while ((loader != null) && (loader != stopLoader)) {@b@ URL[] urls;@b@ int i;@b@ if (loader instanceof URLClassLoader) {@b@ urls = ((URLClassLoader)loader).getURLs();@b@ for (i = 0; i < urls.length; ++i)@b@ {@b@ String jarName = getJarName(urls[i]);@b@@b@ if ((jarName != null) && (!(Matcher.matchName(ignoredJars, jarName))) && (!(urls[i].toString().contains("/WEB-INF/lib/" + jarName))))@b@ {@b@ if (log.isDebugEnabled())@b@ log.debug(sm.getString("jarScan.classloaderJarScan", new Object[] { urls[i] }));@b@ try@b@ {@b@ process(callback, urls[i]);@b@ } catch (IOException ioe) {@b@ log.warn(sm.getString("jarScan.classloaderFail", new Object[] { urls[i] }), ioe);@b@ }@b@@b@ }@b@ else if (log.isTraceEnabled()) {@b@ log.trace(sm.getString("jarScan.classloaderJarNoScan", new Object[] { urls[i] }));@b@ }@b@ }@b@ }@b@@b@ loader = loader.getParent();@b@ }@b@ }@b@ }@b@@b@ private void process(JarScannerCallback callback, URL url)@b@ throws IOException@b@ {@b@ if (log.isTraceEnabled()) {@b@ log.trace(sm.getString("jarScan.jarUrlStart", new Object[] { url }));@b@ }@b@@b@ URLConnection conn = url.openConnection();@b@ if (conn instanceof JarURLConnection) {@b@ callback.scan((JarURLConnection)conn);@b@ } else {@b@ String urlStr = url.toString();@b@ if ((urlStr.startsWith("file:")) || (urlStr.startsWith("jndi:")) || (urlStr.startsWith("http:")) || (urlStr.startsWith("https:")))@b@ {@b@ if (urlStr.endsWith(".jar")) {@b@ URL jarURL = new URL("jar:" + urlStr + "!/");@b@ callback.scan((JarURLConnection)jarURL.openConnection());@b@ }@b@ else {@b@ try {@b@ File f = new File(url.toURI());@b@ if ((f.isFile()) && (this.scanAllFiles))@b@ {@b@ URL jarURL = new URL("jar:" + urlStr + "!/");@b@ callback.scan((JarURLConnection)jarURL.openConnection());@b@ } else if ((f.isDirectory()) && (this.scanAllDirectories)) {@b@ File metainf = new File(f.getAbsoluteFile() + File.separator + "META-INF");@b@@b@ if (metainf.isDirectory())@b@ callback.scan(f);@b@ }@b@ }@b@ catch (URISyntaxException e)@b@ {@b@ IOException ioe = new IOException();@b@ ioe.initCause(e);@b@ throw ioe;@b@ }@b@ }@b@ }@b@ }@b@ }@b@@b@ private String getJarName(URL url)@b@ {@b@ int start;@b@ String name = null;@b@@b@ String path = url.getPath();@b@ int end = path.indexOf(".jar");@b@ if (end != -1) {@b@ start = path.lastIndexOf(47, end);@b@ name = path.substring(start + 1, end + 4);@b@ } else if (isScanAllDirectories()) {@b@ start = path.lastIndexOf(47);@b@ name = path.substring(start + 1);@b@ }@b@@b@ return name;@b@ }@b@@b@ static@b@ {@b@ String jarList = System.getProperty("tomcat.util.scan.DefaultJarScanner.jarsToSkip");@b@ if (jarList != null) {@b@ StringTokenizer tokenizer = new StringTokenizer(jarList, ",");@b@ while (tokenizer.hasMoreElements()) {@b@ String token = tokenizer.nextToken().trim();@b@ if (token.length() > 0)@b@ defaultJarsToSkip.add(token);@b@ }@b@ }@b@ }@b@}