• tomcat源码分析二


    接着分析下start()方法:

    Catalina.start() {...
    if (getServer() == null) {
                load();
     getServer().start();...
    }
    StandardServer.startInternal(){
            fireLifecycleEvent(CONFIGURE_START_EVENT, null);
            setState(LifecycleState.STARTING);//设置Server状态 触发lisener监听器
            globalNamingResources.start();
            // Start our defined Services
            synchronized (servicesLock) {
                for (int i = 0; i < services.length; i++) {
                    services[i].start();
                }
            }
    }
    StandardService.startInternal(){...
    setState(LifecycleState.STARTING);
    engine.start();
    executor.start();
    mapperListener.start();//组件添加能监听到
    synchronized (connectorsLock) {
       for (Connector connector: connectors) {
          try {
             // If it has already failed, don't try and start it
             if (connector.getState() != LifecycleState.FAILED) {
             connector.start();...
    }
    

    我们看下engine的启动

    StandardEngine.startInternal(){
    super.startInternal();//ContainerBase...
    }
    ContainerBase.startInternal(){...
            Cluster cluster = getClusterInternal();
            if (cluster instanceof Lifecycle) {
                ((Lifecycle) cluster).start();
            }
            Realm realm = getRealmInternal();
            if (realm instanceof Lifecycle) {
                ((Lifecycle) realm).start();
            }
            Container children[] = findChildren();
            List<Future<Void>> results = new ArrayList<>();
            for (int i = 0; i < children.length; i++) {
                results.add(startStopExecutor.submit(new StartChild(children[i])));//启动子节点
            }
            MultiThrowable multiThrowable = null;
            for (Future<Void> result : results) {
                try {
                    result.get();//完成了所有子组件的启动
                } catch (Throwable e) {
                    log.error(sm.getString("containerBase.threadedStartFailed"), e);...
            if (pipeline instanceof Lifecycle) {// Start the Valves in our pipeline (including the basic), if any
                ((Lifecycle) pipeline).start();//把请求给到容易后通过value(类似阀门),然后责任链形式匹配容器上的value。容器就拿到了这个请求
            }
            setState(LifecycleState.STARTING);
            threadStart();// Start our thread
    ...}
    StandardHost.startInternal(){...
    String errorValve = getErrorReportValveClass();// Set error report valve
    super.startInternal();//Container
    }
    ContainerBase.startInternal(){...
    setState(LifecycleState.STARTING);//激发监听器HostConfig
    }
    

    host启动

    HostConfig.start() {...
    if (host.getDeployOnStartup())
                deployApps();//部署app
    ...}
    deployApps() {
        File appBase = host.getAppBaseFile();
        File configBase = host.getConfigBaseFile();
        // 过滤出 webapp 要部署应用的目录
        String[] filteredAppPaths = filterAppPaths(appBase.list());
        // 部署 xml 描述文件
        deployDescriptors(configBase, configBase.list());
        // 解压 war 包,但是这里还不会去启动应用
        deployWARs(appBase, filteredAppPaths);
        // 处理已经存在的目录,前面解压的 war 包不会再行处理
        deployDirectories(appBase, filteredAppPaths);
    }
    deployDirectory(ContextName cn, File dir) {...
        context.setName(cn.getName());
        context.setPath(cn.getPath());
        context.setWebappVersion(cn.getVersion());
        context.setDocBase(cn.getBaseName());
        host.addChild(context);
    ...}
    

    context启动

    StandardContext.startInternal(){...
    // Send j2ee.state.starting notification
            if (this.getObjectName() != null) {
                Notification notification = new Notification("j2ee.state.starting",
                        this.getObjectName(), sequenceNumber.getAndIncrement());
                broadcaster.sendNotification(notification);
            }...
        postWorkDirectory();// Post work directory 配置工作目录
        fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);// Notify our interested LifecycleListeners 触发ContextConfig
    ...}
    ContextConfig.webConfig() {...
            WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
                    context.getXmlValidation(), context.getXmlBlockExternal());
            Set<WebXml> defaults = new HashSet<>();
            defaults.add(getDefaultWebXmlFragment(webXmlParser));
            WebXml webXml = createWebXml();     
            InputSource contextWebXml = getContextWebXmlSource();// Parse context level web.xml
            if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
                ok = false;
            }...
            // Step 1. Identify all the JARs packaged with the application and those
            // provided by the container. If any of the application JARs have a
            // web-fragment.xml it will be parsed at this point. web-fragment.xml
            // files are ignored for container provided JARs.
            Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser);
            // Step 2. Order the fragments.
            Set<WebXml> orderedFragments = null;
            orderedFragments =
                    WebXml.orderWebFragments(webXml, fragments, sContext);
            // Step 3. Look for ServletContainerInitializer implementations
            if (ok) {
                processServletContainerInitializers();
            }
            if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
                // Steps 4 & 5.
                processClasses(webXml, orderedFragments);//没有配置时,里面有处理注解式(servelt3)的
            }
    if (!webXml.isMetadataComplete()) {
                // Step 6. Merge web-fragment.xml files into the main web.xml
                // file.
                if (ok) {
                    ok = webXml.merge(orderedFragments);
                }
                // Step 7. Apply global defaults
                // Have to merge defaults before JSP conversion since defaults
                // provide JSP servlet definition.
                webXml.merge(defaults);
                // Step 8. Convert explicitly mentioned jsps to servlets
                if (ok) {
                    convertJsps(webXml);
                }
                // Step 9. Apply merged web.xml to Context
                if (ok) {
                    configureContext(webXml);
                }
    ...}
    processAnnotationsWebResource() {...
    processAnnotationsStream(is, fragment, handlesTypesOnly, javaClassCache);
    ...}
    processAnnotationsStream{...
     ClassParser parser = new ClassParser(is);//解析,并没有立刻加载到jvm,使用的时候在加载
            JavaClass clazz = parser.parse();
            checkHandlesTypes(clazz, javaClassCache);
            if (handlesTypesOnly) {
                return;
            }
            processClass(fragment, clazz);
    ...}
    configureContext(){...
    for (FilterMap filterMap : webxml.getFilterMappings()) {
                context.addFilterMap(filterMap);
            }
            context.setJspConfigDescriptor(webxml.getJspConfigDescriptor());
            for (String listener : webxml.getListeners()) {
                context.addApplicationListener(listener);
            }...
    context.addChild(wrapper);//line 1380 添加了wrapper(servlet)
    ...}
    
    StandardContext.startInternal(){...
    // Start our child containers, if not already started
          for (Container child : findChildren()) {
             if (!child.getState().isAvailable()) {
                 child.start();
             }
          }
    ...}
    

    后续severlet的加载,优先级 warpper load方法等:

    
    

    容器组件启动会触发lisener监听器从而知道容器中发生了变化(如:热部署)。

  • 相关阅读:
    Linux学习路径 -- 1、文件目录操作命令
    第一次认识Postman
    接口测试的基础理论
    浅浅记录一哈HTTP接口
    Linux 的安装和使用
    QTP11 安装笔记:win10
    fiddler的下载安装与配置
    adb 下载安装
    maven 下载 安装 环境配置
    idea 2018.3.4安装破解
  • 原文地址:https://www.cnblogs.com/leifonlyone/p/12752595.html
Copyright © 2020-2023  润新知