大发快3_快3app苹果_大发快3app苹果 - 大发快3,快3app苹果,大发快3app苹果是一个基于本地城市资讯管理的应用,里面汇集了所在城市最热门的民生资讯和便民服务功能,想知道你的家乡发生了什么,打开大发快3,快3app苹果,大发快3app苹果尽在掌握!

Tomcat源码分析 (五)

  • 时间:
  • 浏览:2

在研究tomcat 类加载事先,亲戚亲戚朋友复习一下以后 说巩固一下java 默认的类加载器。楼主事先对类加载也是懵懵懂懂,借此以后 ,也好好复习一下。

楼主翻开了神书《深入理解Java虚拟机》第二版,p227, 关于类加载器的帕累托图。请看:

那此是类加载机制?

Java虚拟机把描述类的数据从Class文件加载进内存,并对数据进行校验,转换解析和初始化,最终形成还都要呗虚拟机直接使用的Java类型,这而是虚拟机的类加载机制。

虚拟机设计团队把类加载阶段中的“通过另另有另一个 类的全限定名来获取描述此类的二进制字节流”你你这个动作贴到 Java虚拟机内部去实现,以便让应用应用程序运行此人 决定怎么才能 才能 去获取所都要的类。实现这动作的代码模块成为“类加载器”。

类与类加载器的关系

类加载器我觉得只用于实现类的加载动作,但它在Java应用应用程序中起到的作用却远远不限于类加载阶段。对于任意另另有另一个 类,都都要由加载他的类加载器和你你这个类四种 生活一起确立其在Java虚拟机中的唯一性,每另另有另一个 类加载器,都拥有另另有另一个 独立的类命名空间。这句话还都要表达的更通俗有些:比较另另有另一个 类不是 “相等”,还时会 时会 在这另另有另一个 类是由同另另有另一个 类加载器加载的前提下才有意义,以后 ,即使这另另有另一个 类来自同另另有另一个 Class文件,被同另另有另一个 虚拟机加载,我希望加载亲戚亲戚朋友的类加载器不同,那你你这个另另有另一个 类就必定不相等。

那此是双亲委任模型?

  1. 从Java虚拟机的宽度来说,只指在四种 生活不同类加载器:四种 生活是启动类加载器(Bootstrap ClassLoader),你你这个类加载器使用C++语言实现(只限HotSpot),是虚拟机自身的一帕累托图;另四种 生活而是所有有些的类加载器,那此类加载器都由Java语言实现,独立于虚拟机内部,以后 有些有些有些有些继承自抽象类java.lang.ClassLoader.

  2. 从Java开发人员的宽度来看,类加载还还都要划分的更细致有些,绝大帕累托图Java应用应用程序员都在使用以下3种系统提供的类加载器:

    • 启动类加载器(Bootstrap ClassLoader):你你这个类加载器繁复将存贴到 JAVA_HOME/lib 目录中的,以后 被-Xbootclasspath 参数所指定的路径种的,以后 是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使贴到 lib目录下而是会重载)。
    • 扩展类加载器(Extension ClassLoader):你你这个类加载器由sun.misc.Launcher$ExtClassLoader实现,它负责夹杂JAVA_HOME/lib/ext 目录下的,以后 被java.ext.dirs 系统变量所指定的路径种的所有类库。开发者还都要直接使用扩展类加载器。
    • 应用应用程序运行类加载器(Application ClassLoader):你你这个类加载器由sun.misc.Launcher$AppClassLoader 实现。以后 你你这个类加载器是ClassLoader 种的getSystemClassLoader措施的返回值,有些有些也成为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库。开发者还都要直接使用你你这个类加载器,以后 应用中那么定义过此人 的类加载器,一般清况 下你你这个而是应用应用程序中默认的类加载器。

那此类加载器之间的关系一般如下图所示:

图中各个类加载器之间的关系成为 类加载器的双亲委派模型(Parents Dlegation Mode)。双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都应当由此人 的父类加载器加载,这里类加载器之间的父子关系一般时会以继承的关系来实现,而是都使用组合关系来复用父加载器的代码。

类加载器的双亲委派模型在JDK1.2 期间被引入并被广泛应用于事先的所有Java应用应用程序中,但他并都在个强制性的约束模型,而是Java设计者推荐给开发者的四种 生活类加载器实现措施。

双亲委派模型的工作过程是:以后 另另有另一个 类加载器收到了类加载的请求,他首先时会此人 去尝试加载你你这个类,而是把你你这个请求委派父类加载器去完成。每另另有另一个 层次的类加载器都在那么,以后 所有的加载请求最终都应该传送到顶层的启动类加载器中,还时会 时会 当父加载器反馈此人 无法完成你你这个请求(他的搜索范围中那么找到所需的类)时,子加载器才会尝试此人 去加载。

 为那此要那么做呢?

 以后 那么使用双亲委派模型,由各个类加载器自行加载说说,以后 用户此人 编写了另另有另一个 称为java.lang.Object的类,并贴到 应用应用程序的ClassPath中,那系统以后 老出多个不同的Object类, Java类型体系中最基础的行为就无法保证。应用应用程序运行也以后 变得一片混乱。

双亲委任模型时怎么才能 才能 实现的?

非常简单:所有的代码都在java.lang.ClassLoader中的loadClass措施之中,代码如下:

先检查不是 以后 被加载过,若那么加载则调用父加载器的loadClass措施, 如父加载器为空则默认使用启动类加载器作为父加载器。以后 父类加载失败,抛出ClassNotFoundException 异常后,再调用此人 的findClass措施进行加载。

怎么才能 才能 破坏双亲委任模型?

双亲委任模型都在另另有另一个 强制性的约束模型,而是另另有另一个 建议型的类加载器实现措施。在Java的世界中大帕累托图的类加载器都遵循者模型,但都在例外,到目前为止,双亲委派模型有过3次大规模的“被破坏”的清况 。

第一次:在双亲委派模型老出事先-----即JDK1.2发布事先。

第二次:是你你这个模型自身的不足是因为 的。亲戚亲戚朋友说,双亲委派模型很好的正确处理了各个类加载器的基础类的统一疑问(越基础的类由越上层的加载器进行加载),基础类四种 生活称为“基础”,是以后 它们经常 作为被用户代码调用的API, 但那么绝对,以后 基础类调用会用户的代码缘何办呢?

这都在那么以后 的。另另有另一个 典型的例子而是JNDI服务,JNDI现在以后 是Java的标准服务,它的代码由启动类加载器去加载(在JDK1.3时就贴到 去的rt.jar),但它都要调用由独立厂商实现并部署在应用应用程序运行的ClassPath下的JNDI接口提供者(SPI, Service Provider Interface)的代码,但启动类加载器不以后 “认识“那此代码啊。以后 那此类找不到rt.jar中,以后 启动类加载器又都要加载。缘何办呢?

为了正确处理你你这个疑问,Java设计团队只好引入了另另有另一个 不太优雅的设计:应用应用程序上下文类加载器(Thread Context ClassLoader)。你你这个类加载器还都要通过java.lang.Thread类的setContextClassLoader措施进行设置。以后 创建应用应用程序时还未设置,它以后 从父应用应用程序中继承另另有另一个 ,以后 在应用应用程序运行的全局范围内都那么设置很多说说,那你你这个类加载器默认即使应用应用程序运行类加载器。

嘿嘿,有了应用应用程序上下文加载器,JNDI服务使用你你这个应用应用程序上下文加载器去加载所都要的SPI代码,也而是父类加载器请求子类加载器去完成类加载的动作,你你这个行为实际上而是打通了双亲委派模型的层次型态来逆向使用类加载器,实际上以后 违背了双亲委派模型的一般性原则。但这无可奈何,Java中所有涉及SPI的加载动作基本胜都采用你你这个措施。同类JNDI,JDBC,JCE,JAXB,JBI等。

第三次:为了实现热插拔,热部署,模块化,意思是加进另另有另一个 功能或减去另另有另一个 功能时会重启,只都要把这模块连同类加载器一起换掉就实现了代码的热替换。

Tomcat 的类加载器是缘何设计的?

首先,亲戚亲戚朋友来问个疑问:

Tomcat 以后 使用默认的类加载机制行不行?

亲戚亲戚朋友思考一下:Tomcat是个web容器, 那么它要正确处理那此疑问:

  1. 另另有另一个 web容器以后 都要部署另另有另一个 应用应用程序运行,不同的应用应用程序运行以后 会依赖同另另有另一个 第三方类库的不同版本,还时会 要求同另另有另一个 类库在同另另有另一个 服务器还时会 时会 一份,以后 要保证每个应用应用程序运行的类库都在独立的,保证相互隔离。
  2. 部署在同另另有另一个 web容器中相同的类库相同的版本还都要共享。以后 ,以后 服务器有10个应用应用程序运行,那么要有10份相同的类库加载进虚拟机,这是扯淡的。
  3. web容器都在此人 依赖的类库,还时会 于应用应用程序运行的类库混淆。基于安全考虑,应该让容器的类库和应用应用程序的类库隔一蹶不振 来。
  4. web容器要支持jsp的修改,亲戚亲戚朋友知道,jsp 文件最终也是要编译成class文件时会 在虚拟机中运行,但应用应用程序运行后修改jsp以后 是司空见惯的事情,以后 要你何用? 有些有些,web容器都要支持 jsp 修改后时会重启。

再看看亲戚亲戚朋友的疑问:Tomcat 以后 使用默认的类加载机制行不行?

答案是不行的。为那此?亲戚亲戚朋友看,第另另有另一个 疑问,以后 使用默认的类加载器机制,那么是无法加载另另有另一个 相同类库的不同版本的,默认的类加器是不管你是那此版本的,只在乎你的全限定类名,以后 还时会 时会 一份。第3个疑问,默认的类加载器是时会 实现的,以后 他的职责而是保证唯一性。第另另有另一个 疑问和第另另有另一个 疑问一样。亲戚亲戚朋友再看第3个疑问,亲戚亲戚朋友想亲戚亲戚朋友要缘何实现jsp文件的热修改(楼主起的名字),jsp 文件我觉得也而是class文件,那么以后 修改了,但类名还是一样,类加载器会直接取措施区中以后 指在的,修改后的jsp是时会重新加载的。那么缘何办呢?亲戚亲戚朋友还都要直接卸载掉这jsp文件的类加载器,有些有些你应该想到了,每个jsp文件对应另另有另一个 唯一的类加载器,当另另有另一个 jsp文件修改了,就直接卸载你你这个jsp类加载器。重新创建类加载器,重新加载jsp文件。

Tomcat 怎么才能 才能 实现此人 独特的类加载机制?

亲戚亲戚朋友看看亲戚亲戚朋友的设计图:

亲戚亲戚朋友在这张图中看了有些有些类加载器,除了Jdk自带的类加载器,亲戚亲戚朋友尤其关心Tomcat自身持有的类加载器。仔细有些亲戚亲戚朋友很容易发现:Catalina类加载器和Shared类加载器,亲戚亲戚朋友并都在父子关系,而是兄弟关系。缘何原本设计,亲戚亲戚朋友得分析一下每个类加载器的用途,时会 知晓。

  1. Common类加载器,负责加载Tomcat和Web应用都复用的类
  2. Catalina类加载器,负责加载Tomcat专用的类,而那此被加载的类在Web应用中将不可见
  3. Shared类加载器,负责加载Tomcat下所有的Web应用应用程序运行都复用的类,而那此被加载的类在Tomcat中将不可见
  4. WebApp类加载器,负责加载具体的某个Web应用应用程序运行所使用到的类,而那此被加载的类在Tomcat和有些的Web应用应用程序运行都将不可见
  5. Jsp类加载器,每个jsp页面另另有另一个 类加载器,不同的jsp页面有不同的类加载器,方便实现jsp页面的热插拔

源码阅读

Tomcat启动的入口在Bootstrap的main()措施main()措施执行前,必然先执行其static{}块。有些有些亲戚亲戚朋友首先分析static{}块,以后 分析main()措施

Bootstrap.static{}

static {
    // 获取用户目录
    // Will always be non-null
    String userDir = System.getProperty("user.dir");

    // 第一步,从环境变量中获取catalina.home,在那么获取到的事先将执行后面
的获取操作
    // Home first
    String home = System.getProperty(Globals.CATALINA_HOME_PROP);
    File homeFile = null;

    if (home != null) {
        File f = new File(home);
        try {
            homeFile = f.getCanonicalFile();
        } catch (IOException ioe) {
            homeFile = f.getAbsoluteFile();
        }
    }

    // 第二步,在第一步没获取的事先,从bootstrap.jar所在目录的上一级目录获取
    if (homeFile == null) {
        // First fall-back. See if current directory is a bin directory
        // in a normal Tomcat install
        File bootstrapJar = new File(userDir, "bootstrap.jar");

        if (bootstrapJar.exists()) {
            File f = new File(userDir, "..");
            try {
                homeFile = f.getCanonicalFile();
            } catch (IOException ioe) {
                homeFile = f.getAbsoluteFile();
            }
        }
    }

    // 第三步,第二步中的bootstrap.jar以后

不指在,这时亲戚亲戚朋友直接把user.dir作为亲戚亲戚朋友的home目录
    if (homeFile == null) {
        // Second fall-back. Use current directory
        File f = new File(userDir);
        try {
            homeFile = f.getCanonicalFile();
        } catch (IOException ioe) {
            homeFile = f.getAbsoluteFile();
        }
    }

    // 重新设置catalinaHome属性
    catalinaHomeFile = homeFile;
    System.setProperty(
            Globals.CATALINA_HOME_PROP, catalinaHomeFile.getPath());

    // 接下来获取CATALINA_BASE(从系统变量中获取),若不指在,则将CATALINA_BASE保持和CATALINA_HOME相同
    // Then base
    String base = System.getProperty(Globals.CATALINA_BASE_PROP);
    if (base == null) {
        catalinaBaseFile = catalinaHomeFile;
    } else {
        File baseFile = new File(base);
        try {
            baseFile = baseFile.getCanonicalFile();
        } catch (IOException ioe) {
            baseFile = baseFile.getAbsoluteFile();
        }
        catalinaBaseFile = baseFile;
    }
   // 重新设置catalinaBase属性
    System.setProperty(
            Globals.CATALINA_BASE_PROP, catalinaBaseFile.getPath());
}

亲戚亲戚朋友把代码中的注释搬下来总结一下:

  1. 获取用户目录
  2. 第一步,从环境变量中获取catalina.home,在那么获取到的事先将执行后面 的获取操作
  3. 第二步,在第一步没获取的事先,从bootstrap.jar所在目录的上一级目录获取
  4. 第三步,第二步中的bootstrap.jar以后 不指在,这时亲戚亲戚朋友直接把user.dir作为亲戚亲戚朋友的home目录
  5. 重新设置catalinaHome属性
  6. 接下来获取CATALINA_BASE(从系统变量中获取),若不指在,则将CATALINA_BASE保持和CATALINA_HOME相同
  7. 重新设置catalinaBase属性

简单总结一下,而是加载并设置catalinaHome和catalinaBase相关的信息,以备后续使用。

main()

main措施大体分成两块,一块为init,另一块为load+start

public static void main(String args[]) {
    // 第一块,main措施第一次执行的事先,daemon肯定为null,有些有些直接new了另另有另一个



Bootstrap对象,以后

执行其init()措施
    if (daemon == null) {
        // Don't set daemon until init() has completed
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.init();
        } catch (Throwable t) {
            handleThrowable(t);
            t.printStackTrace();
            return;
        }
        // daemon守护对象设置为bootstrap
        daemon = bootstrap;
    } else {
        // When running as a service the call to stop will be on a new
        // thread so make sure the correct class loader is used to prevent
        // a range of class not found exceptions.
        Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
    }

    // 第二块,执行守护对象的load措施和start措施
    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();
            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) {
        // Unwrap the Exception for clearer error reporting
        if (t instanceof InvocationTargetException &&
                t.getCause() != null) {
            t = t.getCause();
        }
        handleThrowable(t);
        t.printStackTrace();
        System.exit(1);
    }
}

亲戚亲戚朋友点到init()后面 去看看~

public void init() throws Exception {
    // 非常关键的地方,初始化类加载器s,后面
亲戚亲戚朋友会完整篇

具体地分析你你这个措施
    initClassLoaders();

    // 设置上下文类加载器为catalinaLoader,你你这个类加载器负责加载Tomcat专用的类
    Thread.currentThread().setContextClassLoader(catalinaLoader);
    // 暂时略过,后面
会讲
    SecurityClassLoad.securityClassLoad(catalinaLoader);

    // 使用catalinaLoader加载亲戚亲戚朋友的Catalina类
    // 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.getConstructor().newInstance();

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

    // catalina守护对象为刚才使用catalinaLoader加载类、并初始化出来的Catalina对象
    catalinaDaemon = startupInstance;
}

关键的措施initClassLoaders,你你这个措施负责初始化Tomcat的类加载器。通过你你这个措施,亲戚亲戚朋友很容易验证亲戚亲戚朋友上一小节提到的Tomcat类加载图。

private void initClassLoaders() {
    try {
        // 创建commonLoader,以后

未创建成果说说,则使用应用应用程序运行类加载器作为commonLoader
        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,父类加载器为commonLoader
        catalinaLoader = createClassLoader("server", commonLoader);
        // 创建sharedLoader,父类加载器为commonLoader
        sharedLoader = createClassLoader("shared", commonLoader);
    } catch (Throwable t) {
        // 以后

创建的过程中老出异常了,日志记录完成事先直接系统退出
        handleThrowable(t);
        log.error("Class loader creation threw exception", t);
        System.exit(1);
    }
}

所有的类加载器的创建都使用到了措施createClassLoader,有些有些,亲戚亲戚朋友进一步分析一下你你这个措施。createClassLoader用到了CatalinaProperties.getProperty("xxx")措施,你你这个措施用于从conf/catalina.properties文件获取属性值。

private ClassLoader createClassLoader(String name, ClassLoader parent)
    throws Exception {
    // 获取类加载器待加载的位置,以后

为空,则不都要加载特定的位置,使用父类加载返回回去。
    String value = CatalinaProperties.getProperty(name + ".loader");
    if ((value == null) || (value.equals("")))
        return parent;
    // 替换属性变量,比如:${catalina.base}、${catalina.home}
    value = replace(value);

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

   // 解析属性路径变量为仓库路径数组
    String[] repositoryPaths = getPaths(value);

    // 对每个仓库路径进行repositories设置。亲戚亲戚朋友还都要把repositories看成另另有另一个



个待加载的位置对象,还都而是另另有另一个



classes目录,另另有另一个



jar文件目录等等
    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);
}

亲戚亲戚朋友来分析一下ClassLoaderFactory.createClassLoader--类加载器工厂创建类加载器。

public static ClassLoader createClassLoader(List<Repository> repositories,
                                            final ClassLoader parent)
    throws Exception {

    if (log.isDebugEnabled())
        log.debug("Creating new class loader");

    // Construct the "class path" for this class loader
    Set<URL> set = new LinkedHashSet<>();
    // 遍历repositories,对每个repository进行类型判断,并生成URL,每个URL亲戚亲戚朋友都在校验其有效性,有效的URL亲戚亲戚朋友会贴到

URL集合中
    if (repositories != null) {
        for (Repository repository : repositories)  {
            if (repository.getType() == RepositoryType.URL) {
                URL url = buildClassLoaderUrl(repository.getLocation());
                if (log.isDebugEnabled())
                    log.debug("  Including URL " + url);
                set.add(url);
            } else if (repository.getType() == RepositoryType.DIR) {
                File directory = new File(repository.getLocation());
                directory = directory.getCanonicalFile();
                if (!validateFile(directory, RepositoryType.DIR)) {
                    continue;
                }
                URL url = buildClassLoaderUrl(directory);
                if (log.isDebugEnabled())
                    log.debug("  Including directory " + url);
                set.add(url);
            } else if (repository.getType() == RepositoryType.JAR) {
                File file=new File(repository.getLocation());
                file = file.getCanonicalFile();
                if (!validateFile(file, RepositoryType.JAR)) {
                    continue;
                }
                URL url = buildClassLoaderUrl(file);
                if (log.isDebugEnabled())
                    log.debug("  Including jar file " + url);
                set.add(url);
            } else if (repository.getType() == RepositoryType.GLOB) {
                File directory=new File(repository.getLocation());
                directory = directory.getCanonicalFile();
                if (!validateFile(directory, RepositoryType.GLOB)) {
                    continue;
                }
                if (log.isDebugEnabled())
                    log.debug("  Including directory glob "
                        + directory.getAbsolutePath());
                String filenames[] = directory.list();
                if (filenames == null) {
                    continue;
                }
                for (int j = 0; j < filenames.length; j++) {
                    String filename = filenames[j].toLowerCase(Locale.ENGLISH);
                    if (!filename.endsWith(".jar"))
                        continue;
                    File file = new File(directory, filenames[j]);
                    file = file.getCanonicalFile();
                    if (!validateFile(file, RepositoryType.JAR)) {
                        continue;
                    }
                    if (log.isDebugEnabled())
                        log.debug("    Including glob jar file "
                            + file.getAbsolutePath());
                    URL url = buildClassLoaderUrl(file);
                    set.add(url);
                }
            }
        }
    }

    // Construct the class loader itself
    final URL[] array = set.toArray(new URL[set.size()]);
    if (log.isDebugEnabled())
        for (int i = 0; i < array.length; i++) {
            log.debug("  location " + i + " is " + array[i]);
        }

    // 从这儿看,最终所有的类加载器都在URLClassLoader的对象~~
    return AccessController.doPrivileged(
            new PrivilegedAction<URLClassLoader>() {
                @Override
                public URLClassLoader run() {
                    if (parent == null)
                        return new URLClassLoader(array);
                    else
                        return new URLClassLoader(array, parent);
                }
            });
}

亲戚亲戚朋友以后 对initClassLoaders分析完了,接下来分析SecurityClassLoad.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;
    }

    loadCorePackage(loader);
    loadCoyotePackage(loader);
    loadLoaderPackage(loader);
    loadRealmPackage(loader);
    loadServletsPackage(loader);
    loadSessionPackage(loader);
    loadUtilPackage(loader);
    loadValvesPackage(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");
}

这儿我觉得而是使用catalinaLoader加载tomcat源代码后面 的各个专用类。亲戚亲戚朋友大致罗列一下待加载的类所在的package:

  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. org.apache.catalina.valves.*
  9. javax.servlet.http.Cookie
  10. org.apache.catalina.connector.*
  11. org.apache.tomcat.*

好了,至此亲戚亲戚朋友以后 分析完了init后面 涉及到的哪几只关键措施

WebApp类加载器

到这儿,亲戚亲戚朋友隐隐感觉到少分析了点那此!没错,而是WebApp类加载器。整个启动过程分析下来,亲戚亲戚朋友仍然那么看了你你这个类加载器。它又是在哪儿老出的呢?

亲戚亲戚朋友知道WebApp类加载器是Web应用私有的,而每个Web应用我觉得不是 另另有另一个 Context,那么亲戚亲戚朋友通过Context的实现类应该还都要发现。在Tomcat中,Context的默认实现为StandardContext,亲戚亲戚朋友看看你你这个类的startInternal()措施,在这儿亲戚亲戚朋友发现了亲戚亲戚朋友感兴趣的WebApp类加载器。

protected synchronized void startInternal() throws LifecycleException {
    if (getLoader() == null) {
        WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
        webappLoader.setDelegate(getDelegate());
        setLoader(webappLoader);
    }
}

入口代码非常简单,而是webappLoader不指在的事先创建另另有另一个 ,并调用setLoader措施。

总结

亲戚亲戚朋友终于完整篇 地分析完了Tomcat的整个启动过程+类加载过程。也了解并学习了Tomcat不同的类加载机制是为那此要原本设计,带来的附加作用又是怎么才能 才能 的。