02. Tomcat源代码—04. 类加载器

1. Tomcat类加载器图

先给出一张Tomcat中的类加载器图:
Tomcat类加载器

  1. Common ClassLoader:负责加载Tomcat、Web应用都复用的类
  2. Catalina ClassLoader:负责加载Tomcat专用的类,这些类在Web应用中不可见
  3. Shared ClassLoader:负责加载Tomcat下所有Web应用都复用的类,这些类在Tomcat中不可见
  4. WebApp ClassLoader:负责加载具体某个Web应用的类,这些类在Tomcat、其他Web应用中不可见
  5. Jsper ClassLoader:每个jsp页面一个类加载器不同的jsp页面有不同的类加载器,方便实现jsp页面的热插拔

2. 源码分析

Bootstrap.main()

public static void main(String args[]) {

    synchronized (daemonLock) {
    	// main第一次执行时,daemon为null,new Bootstrap(),并执行init。
        if (daemon == null) {
            Bootstrap bootstrap = new Bootstrap();
            try {
                bootstrap.init();
            } catch (Throwable t) {
                handleThrowable(t);
                t.printStackTrace();
                return;
            }
            // bootstrap赋给daemon
            daemon = bootstrap;
        } else {
            Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
        }
    }

    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);
            // load
            daemon.load(args);
            // start
            daemon.start();
            if (null == daemon.getServer()) {
                System.exit(1);
            }
        } else if (command.equals("stop")) {
            daemon.stopServer(args);
        } else if (command.equals("configtest")) {
            daemon.load(args);
            if (null == daemon.getServer()) {
                System.exit(1);
            }
            System.exit(0);
        } else {
            log.warn("Bootstrap: command \"" + command + "\" does not exist.");
        }
    } catch (Throwable t) {
        if (t instanceof InvocationTargetException &&
                t.getCause() != null) {
            t = t.getCause();
        }
        handleThrowable(t);
        t.printStackTrace();
        System.exit(1);
    }
}

main()分为两块:一块是init、一块是load、start。

接着看init():

public void init() throws Exception {
	// 初始化类加载器
    initClassLoaders();
	
    Thread.currentThread().setContextClassLoader(catalinaLoader);

    SecurityClassLoad.securityClassLoad(catalinaLoader);

	// 使用catalinaLoader加载Catalina类,并创建Catalina类实例startupInstance
    Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
    Object startupInstance = startupClass.getConstructor().newInstance();

	// 设置Catalina类的parentClassLoader属性为sharedLoader
    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
    catalinaDaemon = startupInstance;
}

接下来看initClassLoaders():在其中创建了Common ClassLoader、Catalina ClassLoader、Shared ClassLoader。

private void initClassLoaders() {
    try {
    	// 创建Common ClassLoader,创建时父加载器传入为null,最终是使用URLClassLoader创建的,因此Common ClassLoader的父加载器为AppClassLoader
        commonLoader = createClassLoader("common", null);
        if (commonLoader == null) {
            commonLoader = this.getClass().getClassLoader();
        }
        // 创建Catalina ClassLoader,父加载器为CommonLoader。根据createClassLoader中server.loader为空,返回commonLoader
        catalinaLoader = createClassLoader("server", commonLoader);
        // 创建Shared ClassLoader,父加载器为CommonLoader。根据createClassLoader中shared.loader为空,返回commonLoader
        sharedLoader = createClassLoader("shared", commonLoader);
        // 因此,commonLoader、serverLoader、sharedLoader都是同一个类加载器commonLoader
    } catch (Throwable t) {
        handleThrowable(t);
        log.error("Class loader creation threw exception", t);
        System.exit(1);
    }
}

接下来看SecurityClassLoad.securityClassLoad(catalinaLoader):

public final class SecurityClassLoad {

	public static void securityClassLoad(ClassLoader loader) throws Exception {
	    securityClassLoad(loader, true);
	}


	static void securityClassLoad(ClassLoader loader, boolean requireSecurityManager) throws Exception {
	
	    if (requireSecurityManager && System.getSecurityManager() == null) {
	        return;
	    }
		// 使用Catalina ClassLoader加载目录
	    loadCorePackage(loader);
	    loadCoyotePackage(loader);
	    loadLoaderPackage(loader);
	    loadRealmPackage(loader);
	    loadServletsPackage(loader);
	    loadSessionPackage(loader);
	    loadUtilPackage(loader);
	    loadJavaxPackage(loader);
	    loadConnectorPackage(loader);
	    loadTomcatPackage(loader);
	}
}
private static final void loadCorePackage(ClassLoader loader) throws Exception {
    final String basePackage = "org.apache.catalina.core.";
    loader.loadClass(basePackage + "AccessLogAdapter");
    loader.loadClass(basePackage + "ApplicationContextFacade$PrivilegedExecuteMethod");
    loader.loadClass(basePackage + "ApplicationDispatcher$PrivilegedForward");
    loader.loadClass(basePackage + "ApplicationDispatcher$PrivilegedInclude");
    loader.loadClass(basePackage + "ApplicationPushBuilder");
    loader.loadClass(basePackage + "AsyncContextImpl");
    loader.loadClass(basePackage + "AsyncContextImpl$AsyncRunnable");
    loader.loadClass(basePackage + "AsyncContextImpl$DebugException");
    loader.loadClass(basePackage + "AsyncListenerWrapper");
    loader.loadClass(basePackage + "ContainerBase$PrivilegedAddChild");
    loadAnonymousInnerClasses(loader, basePackage + "DefaultInstanceManager");
    loader.loadClass(basePackage + "DefaultInstanceManager$AnnotationCacheEntry");
    loader.loadClass(basePackage + "DefaultInstanceManager$AnnotationCacheEntryType");
    loader.loadClass(basePackage + "ApplicationHttpRequest$AttributeNamesEnumerator");
}

使用Catalina ClassLoader加载的目录有:

  1. org.apache.catalina.core.*
  2. org.apache.coyote.*
  3. org.apache.catalina.loader.*
  4. org.apache.catalina.realm.*
  5. org.apache.catalina.servlets.*
  6. org.apache.catalina.session.*
  7. org.apache.catalina.util.*
  8. javax.servlet.http.Cookie
  9. org.apache.catalina.connector.*
  10. 10.org.apache.tomcat.*

3. 其他源码分析

Tomcat创建类加载器时用到了createClassLoader。

private ClassLoader createClassLoader(String name, ClassLoader parent) throws Exception {
	
	// 获取类加载器要加载的位置,如果为空,则返回父类加载器
	// 就是从 catalina.properties文件里找 common.loader,shared.loader,server.loader 对应的值
	// 在catalina.properties文件中,common.loader有值,shared.loader、server.loader为空
    String value = CatalinaProperties.getProperty(name + ".loader");
    if ((value == null) || (value.equals("")))
        return parent;

    value = replace(value);

    List<Repository> repositories = new ArrayList<>();

    String[] repositoryPaths = getPaths(value);
	
	// 把Repository看成是一个个待加载类的位置
    for (String repository : repositoryPaths) {
        // 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));
        }
    }

	// 使用类加载器工厂创建类加载器
    return ClassLoaderFactory.createClassLoader(repositories, parent);
}

catalina.properties:

common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"
server.loader=
shared.loader=
public enum RepositoryType {
    DIR,
    GLOB,
    JAR,
    URL
}

public static class Repository {
	// 表示位置
    private final String location;
    // 表示类型:目录、jar集合、jar、url
    private final RepositoryType type;

    public Repository(String location, RepositoryType type) {
        this.location = location;
        this.type = type;
    }

    public String getLocation() {
        return location;
    }

    public RepositoryType getType() {
        return type;
    }
}
public static ClassLoader createClassLoader(List<Repository> repositories, final ClassLoader parent) throws Exception {

	...
    Set<URL> set = new LinkedHashSet<>();

    if (repositories != null) {
        for (Repository repository : repositories)  {
            if (repository.getType() == RepositoryType.URL) {
                URL url = buildClassLoaderUrl(repository.getLocation());
                set.add(url);
            } else if (repository.getType() == RepositoryType.DIR) {
				...
                set.add(url);
            } else if (repository.getType() == RepositoryType.JAR) {
                ...
                set.add(url);
            } else if (repository.getType() == RepositoryType.GLOB) {
                	...
                    set.add(url);
                }
            }
        }
    }

    final URL[] array = set.toArray(new URL[0]);
    ...
    
    return AccessController.doPrivileged(new PrivilegedAction<URLClassLoader>() {
        @Override
        public URLClassLoader run() {
            if (parent == null)
            	// 创建类加载器,创建URLClassLoader时,如果parent为null,则默认parent为AppClassLoader
                return new URLClassLoader(array);
            else
            	// 创建类加载器
                return new URLClassLoader(array, parent);
        }
    });
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Tomcat 8.5.81的源码文件是指完整的Tomcat 8.5.81版本的源代码文件集合。Tomcat是一个由Apache基金会开发的开源Java Servlet容,用于实现Java Servlet和JavaServer Pages (JSP)技术。Tomcat 8.5.81是Tomcat 8.5系列的一个特定版本,而8.5系列是Tomcat 8.x版本的一个分支。 Tomcat 8.5.81的源码文件包含了Tomcat服务的所有实现细节和逻辑。它包括了各个核心组件的源代码,如连接(Connector)、容(Container)、Servlet和JSP引擎等。通过阅读这些源码文件,可以深入了解Tomcat服务是如何处理HTTP请求、解析请求、分发请求到对应的Servlet和JSP等。 源码文件中的每个类都对应着Tomcat服务的不同功能模块。这些文件包含了Java类和接口的定义、方法的实现以及注释说明等。通过研究源码,可以理解到Tomcat的内部工作原理,并可以根据需要进行定制化或扩展开发。 在Tomcat 8.5.81的源码文件中,可能会涉及到线程池、连接池、请求处理流程、安全机制、Session管理、Web应用程序部署等一系列关键组件和功能。此外,还可以进一步了解Apache的Catalina容、Jasper引擎、Apr库等的实现细节。 总而言之,Tomcat 8.5.81的源码文件提供了深入了解Tomcat服务内部实现的机会,可以通过阅读和研究源码,对Tomcat有更全面和深入的认识,并对其进行定制化开发、问题排查和性能优化等方面提供了便利。 ### 回答2: Tomcat 8.5.81的源码文件是用Java编写的,用于构建和运行基于Java Servlet、JavaServer Pages (JSP) 和Java WebSocket 的web应用程序。源码文件包含了Tomcat的核心组件和功能实现。 Tomcat 8.5.81的源码文件主要包括以下几个重要的部分: 1. Connector模块:负责处理与客户端的连接,包括HTTP、HTTPS和AJP协议等。在源码文件中,Connector模块涉及到的类主要包括Connector类、Request类、Response类等。这些类实现了连接的建立、请求的解析和响应的发送等功能。 2. Container模块:负责管理和处理Servlet和JSP等组件,包括请求分发、生命周期管理和会话管理等。在源码文件中,Container模块涉及到的类主要包括Context类、Wrapper类等。这些类实现了Servlet和JSP组件的创建、初始化和处理等功能。 3. Catalina模块:作为Tomcat的核心组件,负责整体的服务管理和控制。Catalina模块涉及到的源码文件比较复杂,包括了容的启动、配置、线程池管理等。其中,Catalina类、Server类和Service类是Catalina模块的主要组成部分。 此外,Tomcat 8.5.81的源码文件还包括了一些辅助的模块和工具类,如日志模块(使用了Commons Logging框架)、认证模块(实现了基本的用户认证和授权)以及内存缓存模块(用于提高性能)等。 值得注意的是,Tomcat 8.5.81的源码文件是一个庞大的项目,包含了数十万行代码。阅读和理解整个源码需要一定的Java和Web开发经验。为了更好地理解和使用Tomcat,建议先熟悉相关的Servlet和JSP编程,并对Java的网络编程有一定的了解。 ### 回答3: Tomcat 8.5.81 是一个非常流行的 Java Web 服务,它的源代码文件是编写 Tomcat 运行的核心部分的文件。 Tomcat源代码文件包含各种 Java 类和配置文件。其中最重要的文件是 Tomcat 的启动类,例如:Catalina、StandardServer 和 Bootstrap。这些类是整个服务的入口点,负责初始化和启动服务。 除了启动类,Tomcat 源码文件还包括了一些核心组件,如连接(Connectors)、容(Containers)、Realm 和 Valve 等。连接负责处理 HTTP 请求和响应,容用于托管网页和应用程序,Realm 用于管理用户认证和授权,Valve 用于在处理请求和响应时添额外的处理逻辑。 此外,Tomcat 的源码文件还包括了一些模块和扩展,用于支持 Tomcat 的各种功能和特性。例如,Catalina 模块提供了 Servlet 容的实现,NIO 模块提供了高效的非阻塞 I/O 功能,WebSocket 模块支持 WebSocket 技术等等。 总而言之,Tomcat 8.5.81 的源码文件是构成整个 Tomcat Web 服务的核心组成部分。通过阅读和理解这些源码文件,开发人员可以深入了解 Tomcat 的工作原理,并在需要的时候进行二次开发或自定义扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值