- 浏览: 30667 次
- 性别:
- 来自: 北京
文章分类
最新评论
Tomcat ClassLoader研究
Tomcat ClassLoader研究 收藏
http://tomcat.apache.org/tomcat-4.1-doc/class-loader-howto.html
Tomcat的ClassLoader层次结构:
Bootstrap | System | Common / \ Catalina Shared / \ Webapp1 Webapp2 ... |
||
源代码如下:
org.apache.catalina.startup.Bootstrap类(tomcat主类)
- public final class Bootstrap {
- // ------------------------------------------------------- Static Variables
- /**
- * Debugging detail level for processing the startup.
- */
- private static int debug = 0;
- // ----------------------------------------------------------- Main Program
- /**
- * The main program for the bootstrap.
- *
- * @param args Command line arguments to be processed
- */
- public static void main(String args[]) {
- // Set the debug flag appropriately
- for (int i = 0; i < args.length; i++) {
- if ("-debug".equals(args[i]))
- debug = 1;
- }
- // Configure catalina.base from catalina.home if not yet set
- if (System.getProperty("catalina.base") == null)
- System.setProperty("catalina.base", getCatalinaHome());
- // Construct the class loaders we will need
- ClassLoader commonLoader = null;
- ClassLoader catalinaLoader = null;
- ClassLoader sharedLoader = null;
- try {
- File unpacked[] = new File[1];
- File packed[] = new File[1];
- File packed2[] = new File[2];
- ClassLoaderFactory.setDebug(debug);
- unpacked[0] = new File(getCatalinaHome(),
- "common" + File.separator + "classes");
- packed2[0] = new File(getCatalinaHome(),
- "common" + File.separator + "endorsed");
- packed2[1] = new File(getCatalinaHome(),
- "common" + File.separator + "lib");
- commonLoader =
- ClassLoaderFactory.createClassLoader(unpacked, packed2, null);
- unpacked[0] = new File(getCatalinaHome(),
- "server" + File.separator + "classes");
- packed[0] = new File(getCatalinaHome(),
- "server" + File.separator + "lib");
- catalinaLoader =
- ClassLoaderFactory.createClassLoader(unpacked, packed,
- commonLoader);
- unpacked[0] = new File(getCatalinaBase(),
- "shared" + File.separator + "classes");
- packed[0] = new File(getCatalinaBase(),
- "shared" + File.separator + "lib");
- sharedLoader =
- ClassLoaderFactory.createClassLoader(unpacked, packed,
- commonLoader);
- } catch (Throwable t) {
- log("Class loader creation threw exception", t);
- System.exit(1);
- }
- Thread.currentThread().setContextClassLoader(catalinaLoader);
- // Load our startup class and call its process() method
- try {
- SecurityClassLoad.securityClassLoad(catalinaLoader);
- // Instantiate a startup class instance
- if (debug >= 1)
- log("Loading startup class");
- Class startupClass =
- catalinaLoader.loadClass
- ("org.apache.catalina.startup.Catalina");
- Object startupInstance = startupClass.newInstance();
- // Set the shared extensions class loader
- if (debug >= 1)
- log("Setting startup class properties");
- String methodName = "setParentClassLoader";
- Class paramTypes[] = new Class[1];
- paramTypes[0] = Class.forName("java.lang.ClassLoader");
- Object paramValues[] = new Object[1];
- paramValues[0] = sharedLoader;
- Method method =
- startupInstance.getClass().getMethod(methodName, paramTypes);
- method.invoke(startupInstance, paramValues);
- // Call the process() method
- if (debug >= 1)
- log("Calling startup class process() method");
- methodName = "process";
- paramTypes = new Class[1];
- paramTypes[0] = args.getClass();
- paramValues = new Object[1];
- paramValues[0] = args;
- method =
- startupInstance.getClass().getMethod(methodName, paramTypes);
- method.invoke(startupInstance, paramValues);
- } catch (Exception e) {
- System.out.println("Exception during startup processing");
- e.printStackTrace(System.out);
- System.exit(2);
- }
- }
其中:
commonLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed2, null);
创建common classloader,以AppClassLoader为父ClassLoader
catalinaLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed,
commonLoader);
创建catalina classloader,以common classloader为父classloader
sharedLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed,
commonLoader);
创建share classloader,以common classloader为父classloader
Thread.currentThread().setContextClassLoader(catalinaLoader);
设置ContextClassLoader为catalina classloader
org.apache.catalina.startup.ClassLoaderFactory类
- public static ClassLoader createClassLoader(File unpacked[],
- File packed[],
- ClassLoader parent)
- throws Exception {
- if (debug >= 1)
- log("Creating new class loader");
- // Construct the "class path" for this class loader
- ArrayList list = new ArrayList();
- // Add unpacked directories
- if (unpacked != null) {
- for (int i = 0; i < unpacked.length; i++) {
- File file = unpacked[i];
- if (!file.isDirectory() || !file.exists() || !file.canRead())
- continue;
- if (debug >= 1)
- log(" Including directory " + file.getAbsolutePath());
- URL url = new URL("file", null,
- file.getCanonicalPath() + File.separator);
- list.add(url.toString());
- }
- }
- // Add packed directory JAR files
- if (packed != null) {
- for (int i = 0; i < packed.length; i++) {
- File directory = packed[i];
- if (!directory.isDirectory() || !directory.exists() ||
- !directory.canRead())
- continue;
- String filenames[] = directory.list();
- for (int j = 0; j < filenames.length; j++) {
- String filename = filenames[j].toLowerCase();
- if (!filename.endsWith(".jar"))
- continue;
- File file = new File(directory, filenames[j]);
- if (debug >= 1)
- log(" Including jar file " + file.getAbsolutePath());
- URL url = new URL("file", null,
- file.getCanonicalPath());
- list.add(url.toString());
- }
- }
- }
- // Construct the class loader itself
- String array[] = (String[]) list.toArray(new String[list.size()]);
- StandardClassLoader classLoader = null;
- if (parent == null)
- classLoader = new StandardClassLoader(array);
- else
- classLoader = new StandardClassLoader(array, parent);
- classLoader.setDelegate(true);
- return (classLoader);
- }
ClassLoaderFactory创建的是StandardClassLoader(org.apache.catalina.loader包中)
由Bootstrap类调用Catalina类的process()方法,再调用execute()方法,再调用start()来启动Server实例。
当Tomcat开启每个Context时,是调用的StandardContext的start()方法,其中:
设置Loader为WebappLoader
- if (getLoader() == null) { // (2) Required by Manager
- if (getPrivileged()) {
- if (debug >= 1)
- log("Configuring privileged default Loader");
- setLoader(new WebappLoader(this.getClass().getClassLoader()));
- } else {
- if (debug >= 1)
- log("Configuring non-privileged default Loader");
- setLoader(new WebappLoader(getParentClassLoader()));
- }
- }
然后调用:bindThread(),设置当前线程的ClassLoader为WebappLoader的ClassLoader,即为WebappClassLoader
- private ClassLoader bindThread() {
- ClassLoader oldContextClassLoader =
- Thread.currentThread().getContextClassLoader();
- if (getResources() == null)
- return oldContextClassLoader;
- Thread.currentThread().setContextClassLoader
- (getLoader().getClassLoader());
- DirContextURLStreamHandler.bind(getResources());
- if (isUseNaming()) {
- try {
- ContextBindings.bindThread(this, this);
- } catch (NamingException e) {
- // Silent catch, as this is a normal case during the early
- // startup stages
- }
- }
- return oldContextClassLoader;
- }
WebappLoader的ClassLoader的赋值如下:
- private String loaderClass =
- "org.apache.catalina.loader.WebappClassLoader";
- ......
- public void start() throws LifecycleException {
- // Validate and update our current component state
- if (started)
- throw new LifecycleException
- (sm.getString("webappLoader.alreadyStarted"));
- if (debug >= 1)
- log(sm.getString("webappLoader.starting"));
- lifecycle.fireLifecycleEvent(START_EVENT, null);
- started = true;
- if (container.getResources() == null)
- return;
- // Register a stream handler factory for the JNDI protocol
- URLStreamHandlerFactory streamHandlerFactory =
- new DirContextURLStreamHandlerFactory();
- try {
- URL.setURLStreamHandlerFactory(streamHandlerFactory);
- } catch (Throwable t) {
- // Ignore the error here.
- }
- // Construct a class loader based on our current repositories list
- try {
- classLoader = createClassLoader();
- classLoader.setResources(container.getResources());
- classLoader.setDebug(this.debug);
- classLoader.setDelegate(this.delegate);
- if (container instanceof StandardContext)
- classLoader.setAntiJARLocking(((StandardContext) container).getAntiJARLocking());
- for (int i = 0; i < repositories.length; i++) {
- classLoader.addRepository(repositories[i]);
- }
- // Configure our repositories
- setRepositories();
- setClassPath();
- setPermissions();
- if (classLoader instanceof Lifecycle)
- ((Lifecycle) classLoader).start();
- // Binding the Webapp class loader to the directory context
- DirContextURLStreamHandler.bind
- ((ClassLoader) classLoader, this.container.getResources());
- } catch (Throwable t) {
- throw new LifecycleException("start: ", t);
- }
- // Validate that all required packages are actually available
- validatePackages();
- // Start our background thread if we are reloadable
- if (reloadable) {
- log(sm.getString("webappLoader.reloading"));
- try {
- threadStart();
- } catch (IllegalStateException e) {
- throw new LifecycleException(e);
- }
- }
- }
- ......
- private WebappClassLoader createClassLoader()
- throws Exception {
- Class clazz = Class.forName(loaderClass);
- WebappClassLoader classLoader = null;
- if (parentClassLoader == null) {
- // Will cause a ClassCast is the class does not extend WCL, but
- // this is on purpose (the exception will be caught and rethrown)
- classLoader = (WebappClassLoader) clazz.newInstance();
- } else {
- Class[] argTypes = { ClassLoader.class };
- Object[] args = { parentClassLoader };
- Constructor constr = clazz.getConstructor(argTypes);
- classLoader = (WebappClassLoader) constr.newInstance(args);
- }
- return classLoader;
- }
在WebappClassLoader中,其findClass的搜索顺序与一般的ClassLoader的搜索顺序不同。
一般的ClassLoader的搜索顺序为:
将其委托给父ClassLoader,如果父ClassLoader不能载入相应类,则才交给自己处理
但是WebappClassLoader中,其是先由自己来处理,如果不行再委托给父ClassLoader
相关源代码如下:
- Class clazz = null;
- try {
- if (debug >= 4)
- log(" findClassInternal(" + name + ")");
- try {
- clazz = findClassInternal(name);
- } catch(ClassNotFoundException cnfe) {
- if (!hasExternalRepositories) {
- throw cnfe;
- }
- } catch(AccessControlException ace) {
- ace.printStackTrace();
- throw new ClassNotFoundException(name);
- } catch (RuntimeException e) {
- if (debug >= 4)
- log(" -->RuntimeException Rethrown", e);
- throw e;
- }
- if ((clazz == null) && hasExternalRepositories) {
- try {
- clazz = super.findClass(name);
- } catch(AccessControlException ace) {
- throw new ClassNotFoundException(name);
- } catch (RuntimeException e) {
- if (debug >= 4)
- log(" -->RuntimeException Rethrown", e);
- throw e;
- }
- }
- if (clazz == null) {
- if (debug >= 3)
- log(" --> Returning ClassNotFoundException");
- throw new ClassNotFoundException(name);
- }
- } catch (ClassNotFoundException e) {
- if (debug >= 3)
- log(" --> Passing on ClassNotFoundException", e);
- throw e;
- }
以下引自tomcat的说明文档,说明了加载类的顺序
Therefore, from the perspective of a web application, class or resource loading looks in the following repositories, in this order:
- /WEB-INF/classes of your web application
- /WEB-INF/lib/*.jar of your web application
- Bootstrap classes of your JVM
- System class loader classses (described above)
- $CATALINA_HOME/common/classes
- $CATALINA_HOME/common/endorsed/*.jar
- $CATALINA_HOME/common/lib/*.jar
- $CATALINA_BASE/shared/classes
- $CATALINA_BASE/shared/lib/*.jar
相关推荐
### Tomcat中的ClassLoader详解 #### 一、引言 在深入了解Tomcat的工作原理时,一个重要的组成部分就是其ClassLoader机制。本文旨在深入剖析Tomcat中特有的类加载器(ClassLoader)体系结构,帮助读者理解Tomcat...
总的来说,深入研究Tomcat 5.0.18的ClassLoader源码,不仅可以提升我们的技术水平,还能让我们更好地应对Java Web开发中的挑战。对于那些想要深入理解Java类加载机制和Tomcat内部工作的开发者,这是一个不可多得的...
《Tomcat类加载机制——ClassLoader详解》 在Java Web开发中,Tomcat作为最常用的Servlet容器,其类加载机制对于...通过阅读和研究Tomcat源码,我们可以更深入地了解这一机制,从而更好地驾驭这个强大的Web服务器。
- **Classloading**:Tomcat使用定制的ClassLoader加载Web应用的类,遵循“父类加载优先”原则。 6. **连接器与协议处理** - **NIO和Apr**:Tomcat提供了多种连接器实现,如基于Java NIO的 Coyote Connector 和...
5. **ClassLoader机制**:Tomcat使用自定义的ClassLoader来加载Web应用程序的类,确保不同应用之间的类隔离,防止冲突。 Tomcat 6.0.18版的特性包括: 1. **性能优化**:相对于之前的版本,6.0.18进行了性能调优,...
4. Common ClassLoader:在Tomcat中,它是所有Web应用共享的类加载器,用于加载`common.loader`配置项指定的类路径。 5. WebApp ClassLoader:每个Web应用有自己的类加载器,它加载应用的`WEB-INF/classes`和`WEB-...
通过研究这个脚本,我们可以了解如何配置JVM参数,如内存分配、堆大小以及设置系统属性,以优化Tomcat的性能。 2. **Tomcat工作原理** Tomcat基于Coyote和Apr(Apache Portable Runtime)处理HTTP请求。Coyote是...
《深入剖析Tomcat》这本书是Java开发者们探索Tomcat服务器内部机制的重要参考资料,它带领读者逐步揭开Tomcat的...通过学习和研究Tomcat源码,我们可以提升技术水平,解决实际问题,甚至为Tomcat社区贡献自己的力量。
5. **ClassLoader机制**:Tomcat的类加载机制允许每个Web应用拥有自己的类加载器,避免类冲突。理解这部分源码对于理解和解决部署问题至关重要。 6. **Session管理**:Tomcat处理用户会话,包括创建、跟踪和管理...
4. 最后,如果所有父类加载器都未能加载,Catalina ClassLoader才加载Tomcat自身的类。 VSD文件可能包含一个流程图,详细描绘了Tomcat类加载器的工作流程和关系,这对于理解类加载机制非常有帮助。通过阅读和分析该...
10. **网络编程**:Tomcat底层使用NIO(非阻塞I/O)和BIO(阻塞I/O)模型,这在`java/org/apache/tomcat/util/net`目录下可以深入研究。 通过学习和分析这些源码,开发者不仅可以提升对Java Web技术的理解,还可以...
通过研究"apache-tomcat-7.0.40-src",开发者可以更好地理解Web服务器的工作流程,定制化自己的Tomcat实例,优化性能,或者为社区贡献代码。对于Java Web开发人员来说,深入学习和理解Tomcat源码是提升技能的重要...
3. **学习部署和加载机制**:Tomcat如何加载和管理Web应用程序,包括WAR文件的部署和Classloader的工作原理。 4. **研究线程模型**:Tomcat如何使用线程来处理并发请求,以及线程池的配置和管理。 5. **深入JSP和...
3. **启动流程**:Tomcat的启动过程始于`bin/catalina.sh`或`catalina.bat`,这些脚本会初始化Java环境,并加载`catalina.jar`中的`org.apache.catalina.startup.ClassLoader`,接着加载`Server`对象,初始化`...
5. **ClassLoader**:Tomcat使用自定义的ClassLoader来加载Web应用的类。这使得不同应用之间能隔离地运行,避免类冲突。 6. **Lifecycle**:所有Tomcat组件都遵循生命周期接口,如`org.apache.catalina.Lifecycle`...
源码中,ClassLoader的实现(例如`org.apache.catalina.loader.WebappClassLoaderBase`)值得深入研究。 5. **部署和配置**:Tomcat支持多种方式部署Web应用,如WAR文件、目录结构或者通过管理接口。源码中,你可以...
总的来说,通过研究Tomcat7的源码Eclipse工程,不仅可以提升Java Web开发的专业技能,还能深入了解服务器架构设计,这对于优化应用性能、排查故障以及定制化开发具有极大的价值。在实践中,我们可以结合官方文档和...
通过对"Tomcat_src"的深入研究,开发者可以提升自己的技术水平,更好地驾驭这个强大的Web服务器。无论是为了学习、调试还是定制,Tomcat源代码都是一份宝贵的资源,值得每一个Java Web开发者珍视。