- 浏览: 206040 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
harim:
思路十分不错,最近两家公司面试都问到了这个问题,我没有答出来, ...
缓存策略之LRU实现(基于双链表实现) -
javatozhang:
楼主真是良苦用心,很可惜我现在才对Tomcat感兴趣并有时间来 ...
tomcat init中加载哪些类? -
javatozhang:
diecui1202 写道可以看看goldendoc.org小 ...
tomcat init思维图 -
cherishLC:
非常感谢~表示自己没用过jquery,如果 jquery地址改 ...
最简单的jQuery折叠菜单 -
zhypengjw2012:
非常感谢!我今天就用到了!
jQuery插件--滑动条
之前有写过关于tomcat中常用的一些类结构的文章。
今天来关注一下,tomcat的类加载器相关的内容。
PS: 由于前一篇文章内容比较简单, 有朋友冠以我标题党之嫌,对于此种说法,本人深感抱歉,可能标题确实有点大,但是这些常用的类,我更多的时候只关注其用法,而忽略了内部实现,所以也就把这些内容总结了一下,发了出来。别无标题党之意,请各位eyer海涵。
OK, 现在进入正题. Tomcat类加载器初始化.
开始之前,我们首先需要了解一下几个基本的知识点;
1.tomcat中类加载器的结构与关系。
这里,我引用tomcat文档的一个简图来说明一下, 有兴趣深究的朋友,可以去翻看tomcat的文档,理解更多信息.
(tomcat5.5)
(由于参考的是tomcat6.0的源代码,这里纠正一下类加载器的图(如下),以免给别的朋友造成误解,同时也多谢asialee给出的提醒)
(tomcat6.0)
2.每种类加载器分别加载什么资源:
这些内容,可以在tomcat文档的 Class Loader HOW-TO 找到.
这里我要说明的是, 在tomcat中,这些内容是记录在哪里的。既(程序怎么让tomcat知道,需要加载哪些类)
答案是-----
其通过一个配置文件来指定的:(catalina.properties),这个文件默认存放在
tomcat路径下的 bin/bootstrap.jar中。
如图
打开文件,其内容如下:
# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when # passed to checkPackageAccess unless the # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans. # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when # passed to checkPackageDefinition unless the # corresponding RuntimePermission ("defineClassInPackage."+package) has # been granted. # # by default, no packages are restricted for definition, and none of # the class loaders supplied with the JDK call checkPackageDefinition. # package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper. # # # List of comma-separated paths defining the contents of the "common" # classloader. Prefixes should be used to define what is the repository type. # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. # If left as blank,the JVM system loader will be used as Catalina's "common" # loader. # Examples: # "foo": Add this folder as a class repository # "foo/*.jar": Add all the JARs of the specified folder as class # repositories # "foo/bar.jar": Add bar.jar as a class repository common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar # # List of comma-separated paths defining the contents of the "server" # classloader. Prefixes should be used to define what is the repository type. # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. # If left as blank, the "common" loader will be used as Catalina's "server" # loader. # Examples: # "foo": Add this folder as a class repository # "foo/*.jar": Add all the JARs of the specified folder as class # repositories # "foo/bar.jar": Add bar.jar as a class repository server.loader= # # List of comma-separated paths defining the contents of the "shared" # classloader. Prefixes should be used to define what is the repository type. # Path may be relative to the CATALINA_BASE path or absolute. If left as blank, # the "common" loader will be used as Catalina's "shared" loader. # Examples: # "foo": Add this folder as a class repository # "foo/*.jar": Add all the JARs of the specified folder as class # repositories # "foo/bar.jar": Add bar.jar as a class repository # Please note that for single jars, e.g. bar.jar, you need the URL form # starting with file:. shared.loader= # # String cache configuration. tomcat.util.buf.StringCache.byte.enabled=true #tomcat.util.buf.StringCache.char.enabled=true #tomcat.util.buf.StringCache.trainThreshold=500000 #tomcat.util.buf.StringCache.cacheSize=5000
此文件,下面会有详细的介绍.
OK,到此,我们初步了解到tomcat关于类加载器的一些知识。 下面来详细看看,tomcat内部是怎么来初始化这些类加载器的吧.
首先, 我们知道, java程序都需要一个入口(main方法), 而在tomcat中,这个入口在
org.apache.catalina.startup.Bootstrap 这个类中。
看其结构:
定位到方法内部:
public static void main(String args[]) { if (daemon == null) { daemon = new Bootstrap(); try { //初始化资源 (今天来了解的.) daemon.init(); } catch (Throwable t) { t.printStackTrace(); return; } } try { //默认为启动 String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); } else if (command.equals("start")) { //设置标识 daemon.setAwait(true); daemon.load(args); //开启 daemon.start(); } else if (command.equals("stop")) { daemon.stopServer(args); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { t.printStackTrace(); } }
在tomcat启动之前, 需要初始化一些系统资源, 初始化的详细工作都定义在init()方法内部了。
OK,我们继续追踪一下。 定位到init()方法中.\
public void init() throws Exception { // Set Catalina path 设置catalina基本路径 setCatalinaHome(); setCatalinaBase(); //初始化类加载器 initClassLoaders(); Thread.currentThread().setContextClassLoader(catalinaLoader); SecurityClassLoad.securityClassLoad(catalinaLoader); // Load our startup class and call its process() method if (log.isDebugEnabled()) log.debug("Loading startup class"); Class startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); // Set the shared extensions class loader if (log.isDebugEnabled()) log.debug("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); catalinaDaemon = startupInstance; }
可以看到, 上面的代码中,用来初始化类加载器、验证类加载器、
以及使用类加载器来加载类"org.apache.catalina.startup.Catalina"等等操作。
这篇文章,主要来探讨一下,tomcat初始化类加载器的方式, ,所以,我们追踪到方法initClassLoaders()中:
这里主要介绍一下,下面的流程, tomcat会调用initClassLoaders()方法。
用来初始化common ,catalina,shared三种类加载器,而这个操作是通过方法
createClassLoader(String name, ClassLoader parent)来完成的。
而后2个都属于common的子级,
所以下面给出2个方法的源代码(其中相关信息,都以注释给出):
/** * 初始化类加载器: * 加载三种: * common. * / \ * catalina shared. */ private void initClassLoaders() { try { //创建common类加载器 commonLoader = createClassLoader("common", null); if( commonLoader == null ) { // no config file, default to this loader - we might be in a 'single' env. commonLoader=this.getClass().getClassLoader(); } //创建catalina类加载器,指定其父级别的加载器为commonLoader. catalinaLoader = createClassLoader("server", commonLoader); //创建sharedLoader类加载器,指定其父级别的加载器为commonLoader. sharedLoader = createClassLoader("shared", commonLoader); } catch (Throwable t) { log.error("Class loader creation threw exception", t); System.exit(1); } }
/** * 创建类加载器 * * @param name * @param parent 指定上一级别的类加载器 * @return * @throws Exception */ private ClassLoader createClassLoader(String name, ClassLoader parent) throws Exception { //这里以common为例: 从catalina.properties中获取common.loader 类加载信息 //如: //common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar String value = CatalinaProperties.getProperty(name + ".loader"); // 如果没有任何信息,则返回父加载器 if ((value == null) || (value.equals(""))) return parent; ArrayList repositoryLocations = new ArrayList(); ArrayList repositoryTypes = new ArrayList(); int i; //以逗号分隔. StringTokenizer tokenizer = new StringTokenizer(value, ","); while (tokenizer.hasMoreElements()) { String repository = tokenizer.nextToken(); // Local repository boolean replace = false; String before = repository; //是否含有"${catalina.home}" while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) { replace=true; if (i>0) { //替换成tomcat路径 替换后的形式如下: c:/opensource/tomcat5/lib. repository = repository.substring(0,i) + getCatalinaHome() + repository.substring(i+CATALINA_HOME_TOKEN.length()); } else { repository = getCatalinaHome() + repository.substring(CATALINA_HOME_TOKEN.length()); } } //是否含有"${catalina.base}" while ((i=repository.indexOf(CATALINA_BASE_TOKEN))>=0) { replace=true; if (i>0) { //同上,替换 repository = repository.substring(0,i) + getCatalinaBase() + repository.substring(i+CATALINA_BASE_TOKEN.length()); } else { repository = getCatalinaBase() + repository.substring(CATALINA_BASE_TOKEN.length()); } } if (replace && log.isDebugEnabled()) log.debug("Expanded " + before + " to " + repository); // Check for a JAR URL repository try { URL url=new URL(repository); repositoryLocations.add(repository); repositoryTypes.add(ClassLoaderFactory.IS_URL); continue; } catch (MalformedURLException e) { // Ignore } if (repository.endsWith("*.jar")) { repository = repository.substring (0, repository.length() - "*.jar".length()); repositoryLocations.add(repository); repositoryTypes.add(ClassLoaderFactory.IS_GLOB); } else if (repository.endsWith(".jar")) { repositoryLocations.add(repository); repositoryTypes.add(ClassLoaderFactory.IS_JAR); } else { repositoryLocations.add(repository); repositoryTypes.add(ClassLoaderFactory.IS_DIR); } } String[] locations = (String[]) repositoryLocations.toArray(new String[0]); Integer[] types = (Integer[]) repositoryTypes.toArray(new Integer[0]); //创建类加载器 ClassLoader classLoader = ClassLoaderFactory.createClassLoader (locations, types, parent); // Retrieving MBean server MBeanServer mBeanServer = null; if (MBeanServerFactory.findMBeanServer(null).size() > 0) { mBeanServer = (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; }
到这里,我们可以确定,tomcat文档中的类加载器之间关系是准确的,并非凭空说的。
到这里,我们可能对于createClassLoader()方法的
CatalinaProperties.getProperty(name + ".loader");
有点疑问, 到底tomcat是如果通过配置文件来获取需要初始化类加载器的相关信息的呢/
前面我们看到 catalina.properties中记录了tomcat三种类加载器中分别需要加载一些什么类的信息。
而CatalinaProperties类正是用来解析此文件的,以告诉tomcat,哪种类加载器,加载哪些类。
我们来看看这个类的源代码:
/** * Utility class to read the bootstrap Catalina configuration. * 读取tomcat 的配置文件 catalina.properties * @author Remy Maucherat * @version $Revision: 467222 $ $Date: 2006-10-24 11:17:11 +0800 (星期二, 24 十月 2006) $ */ public class CatalinaProperties { // ------------------------------------------------------- Static Variables private static org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( CatalinaProperties.class ); private static Properties properties = null; static { loadProperties(); } // --------------------------------------------------------- Public Methods /** * Return specified property value. */ public static String getProperty(String name) { return properties.getProperty(name); } /** * Return specified property value. */ public static String getProperty(String name, String defaultValue) { return properties.getProperty(name, defaultValue); } // --------------------------------------------------------- Public Methods /** * 加载配置信息 * Load properties. */ private static void loadProperties() { InputStream is = null; Throwable error = null; //第一步: 从系统变量中查找 try { //getConfigUrl()方法的内容为: System.getProperty("catalina.config"); String configUrl = getConfigUrl(); if (configUrl != null) { is = (new URL(configUrl)).openStream(); } } catch (Throwable t) { // Ignore } //第二步:再从tomcat的conf目录下去找 if (is == null) { try { File home = new File(getCatalinaBase()); File conf = new File(home, "conf"); File properties = new File(conf, "catalina.properties"); is = new FileInputStream(properties); } catch (Throwable t) { // Ignore } } //还没找到: 则从类路径中加载. if (is == null) { try { is = CatalinaProperties.class.getResourceAsStream ("/org/apache/catalina/startup/catalina.properties"); } catch (Throwable t) { // Ignore } } // 到这里的话,如果找到了,就将配置文件中加载过来 if (is != null) { try { properties = new Properties(); properties.load(is); is.close(); } catch (Throwable t) { error = t; } } if ((is == null) || (error != null)) { // Do something log.warn("Failed to load catalina.properties", error); // That's fine - we have reasonable defaults. properties=new Properties(); } //将配置文件的key-value 设置为 系统变量. // Register the properties as system properties Enumeration enumeration = properties.propertyNames(); while (enumeration.hasMoreElements()) { String name = (String) enumeration.nextElement(); String value = properties.getProperty(name); if (value != null) { System.setProperty(name, value); } } } /** * Get the value of the catalina.home environment variable. */ private static String getCatalinaHome() { return System.getProperty("catalina.home", System.getProperty("user.dir")); } /** * Get the value of the catalina.base environment variable. */ private static String getCatalinaBase() { return System.getProperty("catalina.base", getCatalinaHome()); } /** * Get the value of the configuration URL. */ private static String getConfigUrl() { return System.getProperty("catalina.config"); } }
OK, 到此,tomcat初始化类加载器的过程,我们都已经了解了。
可能看到这里,有的人觉得还是不太理解。 好,让我们来总结一下,这个顺序。
我们按照我们平时常用的操作来看;
1.我要启动tomcat .. (调用Bootstrap的main 方法)
(1)tomcat启动之前,需要加载类,需要类加载器。 于是,它去做初始化工作. -----> init()方法.
(2)init()方法开始工作它再去调用------>initClassLoaders()方法.
(3)发现需要初始化3个类型的类加载器,再调用---> createClassLoader(name,parent) ,告诉它,我要初始化哪种类型的,它的老爸是谁。
(4)通过CatalinaProperties 类去联络catalina.properties,获得,这个哪种类加载器加载哪些类的信息。
(5) 完成初始化,并返回.
2.tomcat 加载其他资源(待续),启动成功……
OK, 文章写完了, 这些内容都是本人自己学习的记录,难免有错误之处,还望大家多提意见,希望能跟各位javaeyer共同交流,达到共同提高的目录。
评论
期待你的下篇文章
最近年关,公司比较忙,等忙完一阵子再接着把学习到的知识共享出来。 再次多谢各位的精华帖投票.......
是的,我是参考的tomcat6.0的源代码, 文章中类加载器的图当时是参考的tomcat5.5的文档发上来了。
这里纠正一下我的错误,把tomcat6的最新类加载器图发上来。
另外,对于新的类加载器的各个描述,这里给出链接地址,有兴趣的朋友可以去看看,
http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html
同时也多谢asialee指出错误。
发表评论
-
tomcat 启动解析server.xml 思维图
2011-09-28 01:26 1800tomcat在启动的时候,会去加载并解析server.xml ... -
tomcat init中加载哪些类?
2010-09-19 00:10 1399tomcat初始化过程中,会加载一些安全的类。 那到底会 ... -
tomcat init思维图
2010-09-18 00:23 1767很久没有研究tomcat啦,晚上把代码打开重新研究了一下,看了 ... -
Tomcat生命周期管理
2010-06-19 16:50 2842在之前的 Tomcat 整体架构中可以看到 Tomcat 包含 ... -
Tomcat-整体架构
2010-05-31 01:53 2037似乎JE直接粘贴Word的文章会出现排版问题, 算了, 直接 ... -
tomcat解析之简单web服务器(图)
2010-02-04 01:08 3114之前有javaeyer推荐了一本书《how tomca ... -
解析Tomcat之HttpServlet(截图记录)
2010-01-01 22:10 3793新年之际,正好趁 ...
相关推荐
在Java中,类的加载、验证、解析和初始化都是由ClassLoader来完成的。Tomcat作为一个Web服务器,其类加载机制设计得相当灵活,以便支持不同Web应用之间的隔离和热部署。 Tomcat的类加载机制主要由以下几部分构成: ...
在Web容器(如Tomcat)中,每个Web应用都有自己的类加载器,这样可以确保不同应用的类之间隔离,避免冲突。而在OSGi环境下,类加载器被用来实现模块间的隔离,每个模块(Bundle)都拥有自己的类加载器,实现了更细...
总结来说,Tomcat的启动顺序是一个自底向上,从核心到应用的过程,依次加载Bootstrap、System、Common、Shared和WebApp类加载器,确保了服务的正确初始化和Web应用程序的隔离运行。理解这一启动流程对于调试、优化和...
- **Web容器**:现代Web容器(如Tomcat、Jetty等)广泛使用类加载器来支持多应用共存环境下的隔离性,每个Web应用都有自己的类加载器,这样可以避免不同应用之间的类冲突问题。 - **OSGi**:OSGi是一个Java平台的...
- Tomcat使用自定义的类加载器,如`CommonClassLoader`、`CatalinaClassLoader`等,它们按照特定的层次结构加载类。 5. **初始化容器** - `Catalina`类是Tomcat的主要组件,负责管理所有Web应用。在启动过程中,...
在Java中,主要有三种类型的类加载器:bootstrap classloader(引导类加载器)、extension classloader(扩展类加载器)和app classloader(应用类加载器)。Bootstrap ClassLoader负责加载JRE核心库,Extension ...
4. **Servlet容器**:Catalina是Tomcat的主要部分,负责管理Servlet生命周期,包括加载、实例化、初始化、服务和销毁Servlet。理解Servlet容器的工作原理对于开发和调试Servlet应用至关重要。 5. **线程模型**:...
Tomcat中类的加载探讨了Tomcat如何寻找、加载和初始化Java类,特别是其自定义的类加载器如何运作;Tomcat的启动过程解析了从命令行启动到服务完全就绪的每一步;而容器思想则强调了Tomcat基于组件的架构,尤其是责任...
2. **System ClassLoader**:通常由JVM的`java.class.path`系统属性指向,负责加载`$CATALINA_HOME/bin/bootstrap.jar`中的类库,这些类主要用于初始化Tomcat并执行主方法。 3. **Common ClassLoader**:这个类加载...
2. System类加载器:加载Tomcat自身启动类,如bootstrap.jar。 3. Common类加载器:加载Tomcat和应用共用的类库,如servlet-api.jar。 4. Webapp类加载器:每个Web应用都有自己独特的类加载器,用于加载应用的类和...
这些步骤确保了Tomcat服务器的正确加载和初始化。 ##### 启动流程详解 启动流程则是在加载流程的基础上进一步操作,使Tomcat进入运行状态。启动流程具体步骤如下: 1. **Bootstrap:main(args)** - 启动点,执行...
本文详细介绍了 Java 类加载机制的基本概念,包括类加载的过程、初始化时机、类加载器的工作原理及其分类,并提供了一个自定义类加载器的示例。通过这些内容的学习,可以帮助开发者更好地理解 Java 类加载机制,为...
3. **Servlet生命周期**:Servlet在Tomcat中的生命周期包括加载、初始化、服务、销毁四个阶段。Tomcat通过Servlet容器管理Servlet实例,确保其正确地创建、初始化和销毁。 4. **请求处理**:当一个HTTP请求到达时,...
本文将深入探讨JVM加载Class文件的机制,类加载器的概念及其类型,以及Tomcat服务器特有的类加载机制。 1. JVM加载Class文件的原理机制 JVM加载Class文件的过程分为三个主要阶段:装载、连接和初始化。 - **装载*...
3. 初始化阶段:初始化静态变量和静态代码块,这是类加载的最后一步,确保类的静态成员按预期进行初始化。 类加载器的层级关系如下: - Bootstrap类加载器:加载JDK核心类库,例如rt.jar,它没有父类加载器。 - ...
总结来说,Tomcat 6的启动过程涉及到Bootstrap类的初始化、Catalina类的加载和配置解析,以及Digester的XML解析功能。这个过程保证了Tomcat能够正确地加载和应用配置,启动并运行Java Web应用程序。理解这一过程对于...
Java中的类加载器通常分为三种:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和应用程序类加载器(Application ClassLoader)。它们遵循双亲委派模型,即较低层次的类加载器会将...
9. **Lifecycle**:Tomcat的组件遵循特定的生命周期,包括初始化、启动、暂停、停止和销毁等阶段,这有助于管理和控制组件的状态。 在《Tomcat架构解析》中,你可能会了解到如何配置和优化Tomcat,以提升性能和稳定...
#### Tomcat初始化流程分析 Tomcat是一个流行的Java Servlet容器,用于部署和运行Web应用程序。理解Tomcat的工作原理对于优化应用性能、解决部署问题至关重要。以下是对Tomcat7启动流程的一个深入分析: 1. **启动...