Tomcat的类加载体系及Tomcat源码

本文深入剖析Tomcat的类加载体系,包括Bootstrap、commonLoader、catalinaLoader、sharedLoader及WebappClassLoader等关键组件的工作原理。通过源码级解读,揭示Tomcat如何高效管理和加载各类应用程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

谈谈Tomcat内核- http://blog.youkuaiyun.com/wangyangzhizhou/article/details/77453962

一个脚本(tomcat禁止了通过bat文件来关闭)引发的血案- http://blog.youkuaiyun.com/ityouknow/article/details/59478852
Tomcat进程意外退出的问题分析- http://ifeve.com/why-kill-2-cannot-stop-tomcat/

> 75篇关于Tomcat源码和机制的文章-- http://blog.youkuaiyun.com/wangyangzhizhou/article/details/53944121

>>> Java虚拟机规范中提到的主要类加载器:
  Bootstrap Loader:加载lib目录下或者System.getProperty(“sun.boot.class.path”)、或者-XBootclasspath所指定的路径或jar。
  Extended Loader:加载lib\ext目录下或者System.getProperty(“java.ext.dirs”) 所指定的 路径或jar。在使用Java运行程序时,也可以指定其搜索路径,例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld。
  AppClass Loader:加载System.getProperty("java.class.path")所指定的 路径或jar。在使用Java运行程序时,也可以加上-cp来覆盖原有的Classpath设置,例如: java -cp ./lavasoft/classes HelloWorld。
>>> Tomcat的类加载体系:
  ClassLoader:Java提供的类加载器抽象类,用户自定义的类加载器需要继承实现
  commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
  catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
  sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
  WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;
>>> 源码分析
  commonLoader、catalinaLoader和sharedLoader在Tomcat容器初始化的一开始,即调用Bootstrap的init方法时创建。catalinaLoader会被设置为Tomcat主线程的线程上下文类加载器,并且使用catalinaLoader加载Tomcat容器自身容器下的class。
  >Bootstrap的init方法的部分代码清单如下:
/** 
 * Initialize daemon. 
 */  
public void init()   throws Exception  {  
   // Set Catalina path  
    setCatalinaHome();  
    setCatalinaBase();  
    initClassLoaders();  
    Thread.currentThread().setContextClassLoader(catalinaLoader);  
    SecurityClassLoad.securityClassLoad(catalinaLoader);  
    // 省略后边的代码  
 > 我们接着来看initClassLoaders方法的实现:
private void initClassLoaders() {  
    try {  
        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();  
        }  
        catalinaLoader = createClassLoader("server", commonLoader);  
        sharedLoader = createClassLoader("shared", commonLoader);  
    } catch (Throwable t) {  
        log.error("Class loader creation threw exception", t);  
        System.exit(1);  
    }  
}  
  > 创建类加载器的createClassLoader方法的实现:
private ClassLoader createClassLoader(String name, ClassLoader parent)  throws Exception {  
    String value = CatalinaProperties.getProperty(name + ".loader");  
    if ((value == null) || (value.equals("")))  
        return parent;  
    ArrayList<String> repositoryLocations = new ArrayList<String>();  
    ArrayList<Integer> repositoryTypes = new ArrayList<Integer>();  
    int i;  
    StringTokenizer tokenizer = new StringTokenizer(value, ",");  
    while (tokenizer.hasMoreElements()) {  
        String repository = tokenizer.nextToken();  
        // Local repository  
        boolean replace = false;  
        String before = repository;  
        while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) {  
            replace=true;  
            if (i>0) {  
            repository = repository.substring(0,i) + getCatalinaHome()   
                + repository.substring(i+CATALINA_HOME_TOKEN.length());  
            } else {  
                repository = getCatalinaHome()   
                    + repository.substring(CATALINA_HOME_TOKEN.length());  
            }  
        }  
        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 {  
            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 = repositoryLocations.toArray(new String[0]);  
    Integer[] types = 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 = 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;  
}  
 > createClassLoader最终使用ClassLoaderFactory.createClassLoader(locations, types, parent)方法创建ClassLoader。我们回头看看SecurityClassLoad.securityClassLoad(catalinaLoader)的实现:
public static void securityClassLoad(ClassLoader loader)  throws Exception {  
    if( System.getSecurityManager() == null ){  
        return;  
    }  
    loadCorePackage(loader);  
    loadLoaderPackage(loader);  
    loadSessionPackage(loader);  
    loadUtilPackage(loader);  
    loadJavaxPackage(loader);  
    loadCoyotePackage(loader);          
    loadTomcatPackage(loader);  
}  
 > securityClassLoad方法主要加载Tomcat容器所需的class,包括:
Tomcat核心class,即org.apache.catalina.core路径下的class;
org.apache.catalina.loader.WebappClassLoader$PrivilegedFindResourceByName;
Tomcat有关session的class,即org.apache.catalina.session路径下的class;
Tomcat工具类的class,即org.apache.catalina.util路径下的class;
javax.servlet.http.Cookie;
Tomcat处理请求的class,即org.apache.catalina.connector路径下的class;
Tomcat其它工具类的class,也是org.apache.catalina.util路径下的class;
  > 我们以加载Tomcat核心class的loadCorePackage方法为例,查看其实现:
private final static void loadCorePackage(ClassLoader loader)  throws Exception {  
    String basePackage = "org.apache.catalina.";  
    loader.loadClass   (basePackage +   "core.ApplicationContextFacade$1");  
    loader.loadClass  (basePackage +  "core.ApplicationDispatcher$PrivilegedForward");  
    loader.loadClass  (basePackage +   "core.ApplicationDispatcher$PrivilegedInclude");  
    loader.loadClass  (basePackage +   "core.AsyncContextImpl");  
    loader.loadClass (basePackage +   "core.AsyncContextImpl$AsyncState");  
    loader.loadClass  (basePackage +  "core.AsyncContextImpl$DebugException");  
    loader.loadClass  (basePackage +  "core.AsyncContextImpl$1");  
    loader.loadClass (basePackage +  "core.AsyncContextImpl$2");  
    loader.loadClass  (basePackage +  "core.AsyncListenerWrapper");  
    loader.loadClass  (basePackage +  "core.ContainerBase$PrivilegedAddChild");  
    loader.loadClass  (basePackage +  "core.DefaultInstanceManager$1");  
    loader.loadClass  (basePackage +  "core.DefaultInstanceManager$2");  
    loader.loadClass  (basePackage +  "core.DefaultInstanceManager$3");  
    loader.loadClass  (basePackage +  "core.DefaultInstanceManager$4");  
    loader.loadClass  (basePackage +   "core.DefaultInstanceManager$5");  
    loader.loadClass  (basePackage +  "core.ApplicationHttpRequest$AttributeNamesEnumerator");  
}  
   > 至此,我们还没有看到WebappClassLoader。启动StandardContext的时候会创建WebappLoader,StandardContext的方法startInternal的部分代码如下:
/** 
 * Start this component and implement the requirements 
 * of {@link LifecycleBase#startInternal()}. 
 * 
 * @exception LifecycleException if this component detects a fatal error 
 *  that prevents this component from being used 
 */  
@Override  
protected synchronized void startInternal() throws LifecycleException {  
    // 省略前边的代码   
    if (getLoader() == null) {  
        WebappLoader webappLoader = new WebappLoader(getParentClassLoader());  
        webappLoader.setDelegate(getDelegate());  
        setLoader(webappLoader);  
    }  
   // 省略中间的代码   
   // Start our subordinate components, if any  
   if ((loader != null) && (loader instanceof Lifecycle))  
        ((Lifecycle) loader).start();   
   // 省略后边的代码   
}  
 从上面代码看到最后会调用WebappLoader的start方法,start又调用了startInternal方法,startInternal的实现如下:
/** 
 * Start associated {@link ClassLoader} and implement the requirements 
 * of {@link LifecycleBase#startInternal()}. 
 * 
 * @exception LifecycleException if this component detects a fatal error 
 *  that prevents this component from being used 
 */  
@Override  
protected void startInternal() throws LifecycleException {  
    // Register a stream handler factory for the JNDI protocol  
    URLStreamHandlerFactory streamHandlerFactory =  new DirContextURLStreamHandlerFactory();  
    if (first) {  
        first = false;  
        try {  
            URL.setURLStreamHandlerFactory(streamHandlerFactory);  
        } catch (Exception e) {  
            // Log and continue anyway, this is not critical  
            log.error("Error registering jndi stream handler", e);  
        } catch (Throwable t) {  
            // This is likely a dual registration  
            log.info("Dual registration of jndi stream handler: "   
                     + t.getMessage());  
        }  
    }  
    // Construct a class loader based on our current repositories list  
    try {  
        classLoader = createClassLoader();  
        classLoader.setResources(container.getResources());  
        classLoader.setDelegate(this.delegate);  
        classLoader.setSearchExternalFirst(searchExternalFirst);  
        if (container instanceof StandardContext) {  
            classLoader.setAntiJARLocking(((StandardContext) container).getAntiJARLocking());  
            classLoader.setClearReferencesStatic( ((StandardContext) container).getClearReferencesStatic());  
            classLoader.setClearReferencesStopThreads(  ((StandardContext) container).getClearReferencesStopThreads());  
            classLoader.setClearReferencesStopTimerThreads(((StandardContext) container).getClearReferencesStopTimerThreads());  
            classLoader.setClearReferencesThreadLocals(((StandardContext) container).getClearReferencesThreadLocals());  
        }  
        for (int i = 0; i < repositories.length; i++) {  
            classLoader.addRepository(repositories[i]);  
        }  
   > 最后我们看看createClassLoader的实现:
/** 
 * Create associated classLoader. 
 */  
private WebappClassLoader createClassLoader()  
    throws Exception {  
  
    //loaderClass即字符串org.apache.catalina.loader.WebappClassLoader  
    Class<?> clazz = Class.forName(loaderClass);  
    WebappClassLoader classLoader = null;  
    if (parentClassLoader == null) {  
        parentClassLoader = container.getParentClassLoader();  
    }  
    Class<?>[] argTypes = { ClassLoader.class };  
    Object[] args = { parentClassLoader };  
    Constructor<?> constr = clazz.getConstructor(argTypes);  
    classLoader = (WebappClassLoader) constr.newInstance(args);  
    return classLoader;  

 至此,整个Tomcat的类加载体系构建完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值