• context创建过程解析(二)之deployWARs


    HostConfig.deployApps()
    //在监听到start事件类型,也就是StandardHost调用startInternal
    protected void deployApps() {
    
            File appBase = host.getAppBaseFile();
    //这个值是在触发before_start时间时生成的,默认是tomcat安装目录+engine名+host名
            File configBase = host.getConfigBaseFile();
    //获取host上配置的webapp下的所有文件,默认是webapps目录下的所有文件
            String[] filteredAppPaths = filterAppPaths(appBase.list());
            // Deploy XML descriptors from configBase  发布xml描述文件
            deployDescriptors(configBase, configBase.list());
            // Deploy WARs
            deployWARs(appBase, filteredAppPaths);
            // Deploy expanded folders
            deployDirectories(appBase, filteredAppPaths);
    
        }
    
    deployWARs
    
    protected void deployWARs(File appBase, String[] files) {
    
            if (files == null)
                return;
    
            ExecutorService es = host.getStartStopExecutor();
            List<Future<?>> results = new ArrayList<>();
    
            for (int i = 0; i < files.length; i++) {
    
                if (files[i].equalsIgnoreCase("META-INF"))
                    continue;
                if (files[i].equalsIgnoreCase("WEB-INF"))
                    continue;
                File war = new File(appBase, files[i]);
    //处理war
                if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") &&
                        war.isFile() && !invalidWars.contains(files[i]) ) {
    
                    ContextName cn = new ContextName(files[i], true);
    
                    if (isServiced(cn.getName())) {
                        continue;
                    }
    //如果已经发布
                    if (deploymentExists(cn.getName())) {
                        DeployedApplication app = deployed.get(cn.getName());
                        boolean unpackWAR = unpackWARs;
                        if (unpackWAR && host.findChild(cn.getName()) instanceof StandardContext) {
                            unpackWAR = ((StandardContext) host.findChild(cn.getName())).getUnpackWAR();
                        }
    //如果不需要解压,并且已经发布。那么判断对应的docBase是否已经存在
                        if (!unpackWAR && app != null) {
                            // Need to check for a directory that should not be
                            // there
                            File dir = new File(appBase, cn.getBaseName());
                            if (dir.exists()) {
                                if (!app.loggedDirWarning) {
                                    log.warn(sm.getString(
                                            "hostConfig.deployWar.hiddenDir",
                                            dir.getAbsoluteFile(),
                                            war.getAbsoluteFile()));
                                    app.loggedDirWarning = true;
                                }
                            } else {
                                app.loggedDirWarning = false;
                            }
                        }
                        continue;
                    }
    
                    // Check for WARs with /../ /./ or similar sequences in the name
                    if (!validateContextPath(appBase, cn.getBaseName())) {
                        log.error(sm.getString(
                                "hostConfig.illegalWarName", files[i]));
                        invalidWars.add(files[i]);
                        continue;
                    }
    
                    results.add(es.submit(new DeployWar(this, cn, war)));
                }
            }
    
            for (Future<?> result : results) {
                try {
                    result.get();
                } catch (Exception e) {
                    log.error(sm.getString(
                            "hostConfig.deployWar.threaded.error"), e);
                }
            }
        }
    
    
    HostConfig.deployWAR(cn, war);
    
    protected void deployWAR(ContextName cn, File war) {
    
    // Constants.ApplicationContextXml == META-INF/context.xml
            File xml = new File(host.getAppBaseFile(),
                    cn.getBaseName() + "/" + Constants.ApplicationContextXml);
    
            File warTracker = new File(host.getAppBaseFile(), cn.getBaseName() + Constants.WarTracker);
    
            boolean xmlInWar = false;
            try (JarFile jar = new JarFile(war)) {
                JarEntry entry = jar.getJarEntry(Constants.ApplicationContextXml);
    //判断是否有context.xml在jar包里面
                if (entry != null) {
                    xmlInWar = true;
                }
            } catch (IOException e) {
                /* Ignore */
            }
    
            // If there is an expanded directory then any xml in that directory
            // should only be used if the directory is not out of date and
            // unpackWARs is true. Note the code below may apply further limits
            boolean useXml = false;
            // If the xml file exists then expandedDir must exists so no need to
            // test that here
    //如果对应xml存在,并且允许解压,也就是已经解压了,这个war包没有修改过
            if (xml.exists() && unpackWARs &&
                    (!warTracker.exists() || warTracker.lastModified() == war.lastModified())) {
                useXml = true;
            }
    
            Context context = null;
    //是否需要发布这个context.xml,通过校验
            boolean deployThisXML = isDeployThisXML(war, cn);
    
            try {
    //允许发布这个xml并且仅仅是使用xml并且不允许copyxml到配置目录,如果允许copy到配置目录,那么这个xml可能不是最新的。
                if (deployThisXML && useXml && !copyXML) {
                    synchronized (digesterLock) {
                        try {
                            context = (Context) digester.parse(xml);
                        } catch (Exception e) {
                            log.error(sm.getString(
                                    "hostConfig.deployDescriptor.error",
                                    war.getAbsolutePath()), e);
                        } finally {
                            digester.reset();
                            if (context == null) {
                                context = new FailedContext();
                            }
                        }
                    }
    //设置context.xml配置文件
                    context.setConfigFile(xml.toURI().toURL());
    //允许发布这个context.xml并且这个xml在war包里面
                } else if (deployThisXML && xmlInWar) {
                    synchronized (digesterLock) {
                        try (JarFile jar = new JarFile(war)) {
                            JarEntry entry = jar.getJarEntry(Constants.ApplicationContextXml);
                            try (InputStream istream = jar.getInputStream(entry)) {
                                context = (Context) digester.parse(istream);
                            }
                        } catch (Exception e) {
                            log.error(sm.getString(
                                    "hostConfig.deployDescriptor.error",
                                    war.getAbsolutePath()), e);
                        } finally {
                            digester.reset();
                            if (context == null) {
                                context = new FailedContext();
                            }
                            context.setConfigFile(
                                    UriUtil.buildJarUrl(war, Constants.ApplicationContextXml));
                        }
                    }
    //不允许发布这个context.xml并且这个xml在war包里面的,那么就直接new出一个StandardContext
                } else if (!deployThisXML && xmlInWar) {
                    // Block deployment as META-INF/context.xml may contain security
                    // configuration necessary for a secure deployment.
                    log.error(sm.getString("hostConfig.deployDescriptor.blocked",
                            cn.getPath(), Constants.ApplicationContextXml,
                            new File(host.getConfigBaseFile(), cn.getBaseName() + ".xml")));
                } else {
                    context = (Context) Class.forName(contextClass).getConstructor().newInstance();
                }
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                log.error(sm.getString("hostConfig.deployWar.error",
                        war.getAbsolutePath()), t);
            } finally {
                if (context == null) {
                    context = new FailedContext();
                }
            }
    
            boolean copyThisXml = false;//是否需要复制xml到配置文件夹中
            if (deployThisXML) {//允许发布
                if (host instanceof StandardHost) {
                    copyThisXml = ((StandardHost) host).isCopyXML();
                }
    
                // If Host is using default value Context can override it. context指定的copyXml属性可以覆盖host级别的
                if (!copyThisXml && context instanceof StandardContext) {
                    copyThisXml = ((StandardContext) context).getCopyXML();
                }
    //如果context.xml在war中,并且允许复制这个xml到配置路径,那么就将此context.xml复制到配置文件夹中
                if (xmlInWar && copyThisXml) {
                    // Change location of XML file to config base
                    xml = new File(host.getConfigBaseFile(),
                            cn.getBaseName() + ".xml");
                    try (JarFile jar = new JarFile(war)) {
                        JarEntry entry = jar.getJarEntry(Constants.ApplicationContextXml);
                        try (InputStream istream = jar.getInputStream(entry);
                                FileOutputStream fos = new FileOutputStream(xml);
                                BufferedOutputStream ostream = new BufferedOutputStream(fos, 1024)) {
                            byte buffer[] = new byte[1024];
                            while (true) {
                                int n = istream.read(buffer);
                                if (n < 0) {
                                    break;
                                }
                                ostream.write(buffer, 0, n);
                            }
                            ostream.flush();
                        }
                    } catch (IOException e) {
                        /* Ignore */
                    }
                }
            }
    //下面这部分代码基本和deployDescriptors差不多
            DeployedApplication deployedApp = new DeployedApplication(cn.getName(),
                    xml.exists() && deployThisXML && copyThisXml);
    
            long startTime = 0;
            // Deploy the application in this WAR file
            if(log.isInfoEnabled()) {
                startTime = System.currentTimeMillis();
                log.info(sm.getString("hostConfig.deployWar",
                        war.getAbsolutePath()));
            }
    
            try {
                // Populate redeploy resources with the WAR file
                deployedApp.redeployResources.put
                    (war.getAbsolutePath(), Long.valueOf(war.lastModified()));
    
                if (deployThisXML && xml.exists() && copyThisXml) {
    //这个xml被复制到配置目录
                    deployedApp.redeployResources.put(xml.getAbsolutePath(),
                            Long.valueOf(xml.lastModified()));
                } else {
                    // In case an XML file is added to the config base later 如果配置加载配置目录中才会有效
                    deployedApp.redeployResources.put(
                            (new File(host.getConfigBaseFile(),
                                    cn.getBaseName() + ".xml")).getAbsolutePath(),
                            Long.valueOf(0));
                }
    
                Class<?> clazz = Class.forName(host.getConfigClass());
                LifecycleListener listener = (LifecycleListener) clazz.getConstructor().newInstance();
                context.addLifecycleListener(listener);
    
                context.setName(cn.getName());
                context.setPath(cn.getPath());
                context.setWebappVersion(cn.getVersion());
                context.setDocBase(cn.getBaseName() + ".war");
         host.addChild(context);//与deployDescriptors一样的操作
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                log.error(sm.getString("hostConfig.deployWar.error",
                        war.getAbsolutePath()), t);
            } finally {
                // If we're unpacking WARs, the docBase will be mutated after
                // starting the context
                boolean unpackWAR = unpackWARs;
                if (unpackWAR && context instanceof StandardContext) {
                    unpackWAR = ((StandardContext) context).getUnpackWAR();
                }
    //上面不是已经添加了docBase资源的监控了吗?这里是因为tomcat在解压了war之后会重新定义它的docBase目录,所以需要添加,不管原始的还是新的都要进行监控
                if (unpackWAR && context.getDocBase() != null) {
                    File docBase = new File(host.getAppBaseFile(), cn.getBaseName());
                    deployedApp.redeployResources.put(docBase.getAbsolutePath(),
                            Long.valueOf(docBase.lastModified()));
                    addWatchedResources(deployedApp, docBase.getAbsolutePath(),
                            context);
                    if (deployThisXML && !copyThisXml && (xmlInWar || xml.exists())) {
                        deployedApp.redeployResources.put(xml.getAbsolutePath(),
                                Long.valueOf(xml.lastModified()));
                    }
                } else {
                    // Passing null for docBase means that no resources will be
                    // watched. This will be logged at debug level.
                    addWatchedResources(deployedApp, null, context);
                }
                // Add the global redeploy resources (which are never deleted) at
                // the end so they don't interfere with the deletion process
                addGlobalRedeployResources(deployedApp);
            }
    
            deployed.put(cn.getName(), deployedApp);
    
            if (log.isInfoEnabled()) {
                log.info(sm.getString("hostConfig.deployWar.finished",
                    war.getAbsolutePath(), Long.valueOf(System.currentTimeMillis() - startTime)));
            }
        }
  • 相关阅读:
    集合
    网络
    File类
    laoshi
    石子合并《1》
    看球的巴士
    打鼹鼠~~线性DP
    题目分享:Wooden Sticks-线性动归
    pycharm怎么切换python版本
    Windows10下CMD输入Python没反应的解决方案
  • 原文地址:https://www.cnblogs.com/honger/p/10363043.html
Copyright © 2020-2023  润新知