`

tomcat 源码研究之war工程解析

 
阅读更多

   我们知道tomcat启动 会带动我们自己的应用工程运行,有时候我们的应用工程却是以war形式存在的,那么tomcat 是怎么解析war工程,下面就是我对tomcat源码解析war工程的一些见解

 

1,我们知道tomcat有自己的一套运行周期,他的运行周期如图,

 

而 tomcat运行中,则通过LifecycleSupport类添加各种监听器 其中这些监听器以实现LifecycleListener接口的子类 下图是LifecyceListener的一些子类

 

我在这里重点讲述HostConfig 和ContextConfig  

HostConfig对war工程前期的校验 而ContextConfig对war包的真正解析

LifecycleListener 代码如下

package org.apache.catalina;

public interface LifecycleListener {
    public void lifecycleEvent(LifecycleEvent event);

}

 

2, HostConfig中lifecycleEvent方法如下

 

    public void lifecycleEvent(LifecycleEvent event) {

        // Identify the host we are associated with
        try {
            host = (Host) event.getLifecycle();
            if (host instanceof StandardHost) {
                setCopyXML(((StandardHost) host).isCopyXML());
                setDeployXML(((StandardHost) host).isDeployXML());
                setUnpackWARs(((StandardHost) host).isUnpackWARs());
                setContextClass(((StandardHost) host).getContextClass());
            }
        } catch (ClassCastException e) {
            log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
            return;
        }

        // Process the event that has occurred
        if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
            check();
        } else if (event.getType().equals(Lifecycle.START_EVENT)) {
            start();
        } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
            stop();
        }
    }
此方法中有三个状态  PERIODIC_EVENT START_EVENT STOP_EVENT  而我们知道war工程的解析不可能出现在结束状态 所以只能出现在 PERIODIC_EVENT START_EVENT 即check和start方法

 

下面请看两方法
    protected void check() {

        if (host.getAutoDeploy()) {
            // Check for resources modification to trigger redeployment
            DeployedApplication[] apps =
                deployed.values().toArray(new DeployedApplication[0]);
            for (int i = 0; i < apps.length; i++) {
                if (!isServiced(apps[i].name))
                    checkResources(apps[i]);
            }

            // Check for old versions of applications that can now be undeployed
            if (host.getUndeployOldVersions()) {
                checkUndeploy();
            }

            // Hotdeploy applications
            deployApps();
        }
    }


    public void start() {

        if (log.isDebugEnabled())
            log.debug(sm.getString("hostConfig.start"));

        try {
            ObjectName hostON = host.getObjectName();
            oname = new ObjectName
                (hostON.getDomain() + ":type=Deployer,host=" + host.getName());
            Registry.getRegistry(null, null).registerComponent
                (this, oname, this.getClass().getName());
        } catch (Exception e) {
            log.error(sm.getString("hostConfig.jmx.register", oname), e);
        }

        if (host.getCreateDirs()) {
        	//创建目录<host>中appBase属性下的目录(webapps)和conf/engine/host-name/ 这个目录个
            File[] dirs = new File[] {appBase(),configBase()};
            for (int i=0; i<dirs.length; i++) {
                if (!dirs[i].mkdirs() && !dirs[i].isDirectory()) {
                    log.error(sm.getString("hostConfig.createDirs",dirs[i]));
                }
            }
        }

        if (!appBase().isDirectory()) {
            log.error(sm.getString(
                    "hostConfig.appBase", host.getName(), appBase().getPath()));
            host.setDeployOnStartup(false);
            host.setAutoDeploy(false);
        }

        if (host.getDeployOnStartup())
            deployApps();

    }
 有两个方法可知他们其实最终运行到同一方法上 deployApps方法 代码如下
 protected void deployApps() {
        //appBase属性是Server.xml中host节点的appBase属性 默认是webapps下  
        File appBase = appBase();
        //F:\source\TOMCAT_7_0_57\output\build\conf\Catalina\localhost
        File configBase = configBase();
        //通过appBase.list()可以罗列出host所对应的appBase属性所指的目录下工程
        //过滤appBase属性所指目录下的工程
        String[] filteredAppPaths = filterAppPaths(appBase.list());
        // Deploy XML descriptors from configBase
        //添加部署conf/Catalina/hostName/Context.xml这个context这个
        deployDescriptors(configBase, configBase.list());
        // Deploy WARs
        deployWARs(appBase, filteredAppPaths);
        // Deploy expanded folders
        deployDirectories(appBase, filteredAppPaths);

    }

    /**
     * Deploy WAR files.
     */
    protected void deployWARs(File appBase, String[] files) {

        if (files == null)
            return;

        ExecutorService es = host.getStartStopExecutor();
        List<Future<?>> results = new ArrayList<Future<?>>();

        for (int i = 0; i < files.length; i++) {
            /**
             * 排除webapps 下WEB-INF 和META-INF这种的文件夹
             */
            if (files[i].equalsIgnoreCase("META-INF"))
                continue;
            if (files[i].equalsIgnoreCase("WEB-INF"))
                continue;
            File war = new File(appBase, files[i]);
            //查看webapps下是否有.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;
                }
               //简单校验一下war工程
                if (deploymentExists(cn.getName())) {
                    DeployedApplication app = deployed.get(cn.getName());
                    if (!unpackWARs && 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;
                }
                //执行DeployWar中的run方法
                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);
            }
        }
    }
 最终解析war工程 到了 DeployWar(this, cn, war))这个类中的run方法中
 private static class DeployWar implements Runnable {

        private HostConfig config;
        private ContextName cn;
        private File war;

        public DeployWar(HostConfig config, ContextName cn, File war) {
            this.config = config;
            this.cn = cn;
            this.war = war;
        }

        @Override
        public void run() {
        	//执行HostConfig类中的deyloyWar
            config.deployWAR(cn, war);
        }
    }
 又回到 HostConfig的deployWAR方法中
 /**
     * @param cn
     * @param war
     * 解压war包
     * 最终真正解压war包的却是ContextConfig
     */
    protected void deployWAR(ContextName cn, File war) {

        // Checking for a nested /META-INF/context.xml
        JarFile jar = null;
        InputStream istream = null;
        FileOutputStream fos = null;
        BufferedOutputStream ostream = null;
        //检查War工程下是否有此文件
        File xml = new File(appBase(),
                cn.getBaseName() + "/META-INF/context.xml");

        boolean xmlInWar = false;
        JarEntry entry = null;
        /**
         * 以jar的形式访问War工程 
         */
        try {
            jar = new JarFile(war);
            entry = jar.getJarEntry(Constants.ApplicationContextXml);
            if (entry != null) {
                xmlInWar = true;
            }
        } catch (IOException e) {
            /* Ignore */
        } finally {
            entry = null;
            if (jar != null) {
                try {
                    jar.close();
                } catch (IOException ioe) {
                    // Ignore;
                }
                jar = null;
            }
        }

        Context context = null;
        //解析Context.xml文件中Context节点生成Context接口的类
        /**
         * 正常情况生成StandardContext类 但是也可能出现失败情况 则生成FailedContext类
         */
        try {
            if (deployXML && xml.exists() && !copyXML) {
                synchronized (digesterLock) {
                    try {
                        context = (Context) digester.parse(xml);
                    } catch (Exception e) {
                        log.error(sm.getString(
                                "hostConfig.deployDescriptor.error",
                                war.getAbsolutePath()), e);
                    } finally {
                        if (context == null) {
                            context = new FailedContext();
                        }
                        digester.reset();
                    }
                }
                context.setConfigFile(xml.toURI().toURL());
            } else if (deployXML && xmlInWar) {
                synchronized (digesterLock) {
                    try {
                        jar = new JarFile(war);
                        entry =
                            jar.getJarEntry(Constants.ApplicationContextXml);
                        istream = jar.getInputStream(entry);
                        context = (Context) digester.parse(istream);
                    } catch (Exception e) {
                        log.error(sm.getString(
                                "hostConfig.deployDescriptor.error",
                                war.getAbsolutePath()), e);
                    } finally {
                        if (context == null) {
                            context = new FailedContext();
                        }
                        context.setConfigFile(new URL("jar:" +
                                war.toURI().toString() + "!/" +
                                Constants.ApplicationContextXml));
                        if (istream != null) {
                            try {
                                istream.close();
                            } catch (IOException e) {
                                /* Ignore */
                            }
                            istream = null;
                        }
                        entry = null;
                        if (jar != null) {
                            try {
                                jar.close();
                            } catch (IOException e) {
                                /* Ignore */
                            }
                            jar = null;
                        }
                        digester.reset();
                    }
                }
            } else if (!deployXML && 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(configBase(), cn.getBaseName() + ".xml")));
            } else {
                context = (Context) Class.forName(contextClass).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;
        if (deployXML) {
            if (host instanceof StandardHost) {
                copyThisXml = ((StandardHost) host).isCopyXML();
            }

            // If Host is using default value Context can override it.
            if (!copyThisXml && context instanceof StandardContext) {
                copyThisXml = ((StandardContext) context).getCopyXML();
            }

            if (xmlInWar && copyThisXml) {
                // Change location of XML file to config base
                xml = new File(configBase(), cn.getBaseName() + ".xml");
                entry = null;
                try {
                    jar = new JarFile(war);
                    entry =
                        jar.getJarEntry(Constants.ApplicationContextXml);
                    istream = jar.getInputStream(entry);

                    fos = new FileOutputStream(xml);
                    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 */
                } finally {
                    if (ostream != null) {
                        try {
                            ostream.close();
                        } catch (IOException ioe) {
                            // Ignore
                        }
                        ostream = null;
                    }
                    if (fos != null) {
                        try {
                            fos.close();
                        } catch (IOException ioe) {
                            // Ignore
                        }
                        fos = null;
                    }
                    if (istream != null) {
                        try {
                            istream.close();
                        } catch (IOException ioe) {
                            // Ignore
                        }
                        istream = null;
                    }
                    if (jar != null) {
                        try {
                            jar.close();
                        } catch (IOException ioe) {
                            // Ignore;
                        }
                        jar = null;
                    }
                }
            }
        }

        DeployedApplication deployedApp = new DeployedApplication(cn.getName(),
                xml.exists() && deployXML && copyThisXml);

        long startTime = 0;
        // Deploy the application in this WAR file
        //开始解压war包 并且交给ContextConfig 
        //因为Context 才是真正的应用节点动 Host只是在这里校验 检测路径等  xml文件预设是否完善的等工作的了解
        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 (deployXML && xml.exists() && copyThisXml) {
                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(configBase(),
                                cn.getBaseName() + ".xml")).getAbsolutePath(),
                        Long.valueOf(0));
            }
            //class org.apache.catalina.startup.ContextConfig
            //添加ContextConfig这个监听器
            Class<?> clazz = Class.forName(host.getConfigClass());
            LifecycleListener listener =
                (LifecycleListener) clazz.newInstance();
            context.addLifecycleListener(listener);

            context.setName(cn.getName());
            context.setPath(cn.getPath());
            context.setWebappVersion(cn.getVersion());
            context.setDocBase(cn.getBaseName() + ".war");
            //往Host节点中添加Context节点(从conf/server.xml 我们可知Context是host的一个子节点 这里正常情况下StandardContext)
            host.addChild(context);
        } 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
            if (unpackWARs && context != null && context.getDocBase() != null) {
                File docBase = new File(appBase(), cn.getBaseName());
                deployedApp.redeployResources.put(docBase.getAbsolutePath(),
                        Long.valueOf(docBase.lastModified()));
                addWatchedResources(deployedApp, docBase.getAbsolutePath(),
                        context);
                if (deployXML && !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)));
        }
    }

 至此HostConfig对War解析完成,但是我们也没看到war解压的那一下啊,上面只是对war工程路径,名称,里面包含的Context.xml校验 以及Context节点叫生成,下面请看ContextConfig对象运行流程
 他跟HostConfig一样 我们先看lifecycleEvent方法
  @Override
    public void lifecycleEvent(LifecycleEvent event) {

        // Identify the context we are associated with
        try {
            context = (Context) event.getLifecycle();
        } catch (ClassCastException e) {
            log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);
            return;
        }

        // Process the event that has occurred
        if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
        	//===================3=========================
            configureStart();
        } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
        	//===================2=========================
            beforeStart();
        } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
            // Restore docBase for management tools
            if (originalDocBase != null) {
                context.setDocBase(originalDocBase);
            }
        } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {
            configureStop();
        } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {
        	//===================1=========================
            init();
        } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {
            destroy();
        }

    }
 我们从上述状态中可以知道  只有三个可能   init(); beforeStart();  configureStart(); 按照顺序找 我们找到before_start才是解析war的关键所在
 
 
 
  protected synchronized void beforeStart() {

        try {
        	//整理server.xml中context下这个的docBase这个文件中的目录
            fixDocBase();
        } catch (IOException e) {
            log.error(sm.getString(
                    "contextConfig.fixDocBase", context.getName()), e);
        }

        antiLocking();
    }


 /**
     * Adjust docBase.
     */
    protected void fixDocBase()
        throws IOException {

        Host host = (Host) context.getParent();
        String appBase = host.getAppBase();

        File canonicalAppBase = new File(appBase);
        //检查server.xml中<host>中AppBase属性的值是不是代表一个绝对路径
        if (canonicalAppBase.isAbsolute()) {
            canonicalAppBase = canonicalAppBase.getCanonicalFile();
        } else {
            canonicalAppBase =
                new File(getBaseDir(), appBase)
                .getCanonicalFile();
        }
        //找到server.xml的context中docBase是否存在
        String docBase = context.getDocBase();
        if (docBase == null) {
        	//docBase不存在
        	/*如果path不存在或者"/" 或者"/ROOT"这样的形式
        	 * 那么docBase就为ROOT文件加下
        	 * 如果path存在就是path文件加下 
        	 */
            // Trying to guess the docBase according to the path
            String path = context.getPath();
            if (path == null) {
                return;
            }
            ContextName cn = new ContextName(path, context.getWebappVersion());
            docBase = cn.getBaseName();
        }

        File file = new File(docBase);
        if (!file.isAbsolute()) {
            docBase = (new File(canonicalAppBase, docBase)).getPath();
        } else {
            docBase = file.getCanonicalPath();
        }
        file = new File(docBase);
        String origDocBase = docBase;

        ContextName cn = new ContextName(context.getPath(),
                context.getWebappVersion());
        String pathName = cn.getBaseName();

        boolean unpackWARs = true;
        if (host instanceof StandardHost) {
            unpackWARs = ((StandardHost) host).isUnpackWARs();
            if (unpackWARs && context instanceof StandardContext) {
                unpackWARs =  ((StandardContext) context).getUnpackWAR();
            }
        }
         /**
          * 解压war工程
          */
        if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory()) {
            if (unpackWARs) {
                URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/");
                //正式对xxx.war进行分析生成xxx工程
                docBase = ExpandWar.expand(host, war, pathName);
                file = new File(docBase);
                docBase = file.getCanonicalPath();
                if (context instanceof StandardContext) {
                    ((StandardContext) context).setOriginalDocBase(origDocBase);
                }
            } else {
                URL war =
                        new URL("jar:" + (new File (docBase)).toURI().toURL() + "!/");
                ExpandWar.validate(host, war, pathName);
            }
        } else {
            File docDir = new File(docBase);
            if (!docDir.exists()) {
                File warFile = new File(docBase + ".war");
                if (warFile.exists()) {
                    URL war =
                        new URL("jar:" + warFile.toURI().toURL() + "!/");
                    if (unpackWARs) {
                        docBase = ExpandWar.expand(host, war, pathName);
                        file = new File(docBase);
                        docBase = file.getCanonicalPath();
                    } else {
                        docBase = warFile.getCanonicalPath();
                        ExpandWar.validate(host, war, pathName);
                    }
                }
                if (context instanceof StandardContext) {
                    ((StandardContext) context).setOriginalDocBase(origDocBase);
                }
            }
        }

        if (docBase.startsWith(canonicalAppBase.getPath() + File.separatorChar)) {
            docBase = docBase.substring(canonicalAppBase.getPath().length());
            docBase = docBase.replace(File.separatorChar, '/');
            if (docBase.startsWith("/")) {
                docBase = docBase.substring(1);
            }
        } else {
            docBase = docBase.replace(File.separatorChar, '/');
        }

        context.setDocBase(docBase);

    }
   //正式对xxx.war进行分析生成xxx工程
                docBase = ExpandWar.expand(host, war, pathName);  这段中开始生成真正的工程

 代码如下
 public static String expand(Host host, URL war, String pathname)
        throws IOException {

        // Make sure that there is no such directory already existing
        File appBase = new File(host.getAppBase());
        if (!appBase.isAbsolute()) {
            appBase = new File(System.getProperty(Globals.CATALINA_BASE_PROP),
                               host.getAppBase());
        }
        if (!appBase.exists() || !appBase.isDirectory()) {
            throw new IOException
                (sm.getString("hostConfig.appBase",
                              appBase.getAbsolutePath()));
        }
        
        //工程路径存在吗 存在说明已经解压好了
        File docBase = new File(appBase, pathname);
        if (docBase.exists()) {
            // War file is already installed
            return (docBase.getAbsolutePath());
        }
       //不存在则创建 工程路径,一般以war文件名创建路径
        // Create the new document base directory
        if(!docBase.mkdir() && !docBase.isDirectory())
            throw new IOException(sm.getString("expandWar.createFailed", docBase));

        // Expand the WAR into the new document base directory
        String canonicalDocBasePrefix = docBase.getCanonicalPath();
        if (!canonicalDocBasePrefix.endsWith(File.separator)) {
            canonicalDocBasePrefix += File.separator;
        }
        /**
         * 下面是以jar方式访问war工程中的文件
         * 然后将war工程xxx内部的文件全部复制到工程xxx目录下
         */
        
        JarURLConnection juc = (JarURLConnection) war.openConnection();
        juc.setUseCaches(false);
        JarFile jarFile = null;
        InputStream input = null;
        boolean success = false;
        try {
            jarFile = juc.getJarFile();
            Enumeration<JarEntry> jarEntries = jarFile.entries();
            while (jarEntries.hasMoreElements()) {
                JarEntry jarEntry = jarEntries.nextElement();
                String name = jarEntry.getName();
                File expandedFile = new File(docBase, name);
                if (!expandedFile.getCanonicalPath().startsWith(
                        canonicalDocBasePrefix)) {
                    // Trying to expand outside the docBase
                    // Throw an exception to stop the deployment
                    throw new IllegalArgumentException(
                            sm.getString("expandWar.illegalPath",war, name,
                                    expandedFile.getCanonicalPath(),
                                    canonicalDocBasePrefix));
                }
                int last = name.lastIndexOf('/');
                if (last >= 0) {
                    File parent = new File(docBase,
                                           name.substring(0, last));
                    if (!parent.mkdirs() && !parent.isDirectory()) {
                        throw new IOException(
                                sm.getString("expandWar.createFailed", parent));
                    }
                }
                if (name.endsWith("/")) {
                    continue;
                }
                input = jarFile.getInputStream(jarEntry);

                if(null == input)
                    throw new ZipException(sm.getString("expandWar.missingJarEntry", jarEntry.getName()));

                // Bugzilla 33636
                expand(input, expandedFile);
                long lastModified = jarEntry.getTime();
                if ((lastModified != -1) && (lastModified != 0)) {
                    expandedFile.setLastModified(lastModified);
                }

                input.close();
                input = null;
            }
            success = true;
        } catch (IOException e) {
            throw e;
        } finally {
            if (!success) {
                // If something went wrong, delete expanded dir to keep things 
                // clean
                deleteDir(docBase);
            }
            if (input != null) {
                try {
                    input.close();
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                }
                input = null;
            }
            if (jarFile != null) {
                try {
                    jarFile.close();
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                }
                jarFile = null;
            }
        }

        // Return the absolute path to our new document base directory
        return (docBase.getAbsolutePath());

    }
 上述代码我们可以知道war这样的工程解压是,通过jar形式的api访问war内部文件 然后复制到工程文件夹一种解析
2, 大家有没有注意到 ,平时我们启动了tomat以后 只要修改工程里的文件 马上他就会重新部署这一现象,这是因为tomat 会检测webapps 下工程改动变换,从而调整做出新的部署
代码如下ContainerBase 中threadStart 方法
   protected void threadStart() {

        if (thread != null)
            return;
        if (backgroundProcessorDelay <= 0)
            return;

        threadDone = false;
        String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
        thread = new Thread(new ContainerBackgroundProcessor(), threadName);
        thread.setDaemon(true);
        thread.start();

    }
   ContainerBackgroundProcessor启动容器守护线程 做这一件事,以每隔backgroundProcessorDelay秒的执行 
   protected class ContainerBackgroundProcessor implements Runnable {

        @Override
        public void run() {
            Throwable t = null;
            String unexpectedDeathMessage = sm.getString(
                    "containerBase.backgroundProcess.unexpectedThreadDeath",
                    Thread.currentThread().getName());
            try {
                while (!threadDone) {
                    try {
                        Thread.sleep(backgroundProcessorDelay * 1000L);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                    if (!threadDone) {
                        Container parent = (Container) getMappingObject();
                        ClassLoader cl = 
                            Thread.currentThread().getContextClassLoader();
                        if (parent.getLoader() != null) {
                            cl = parent.getLoader().getClassLoader();
                        }
                        processChildren(parent, cl);
                    }
                }
            } catch (RuntimeException e) {
                t = e;
                throw e;
            } catch (Error e) {
                t = e;
                throw e;
            } finally {
                if (!threadDone) {
                    log.error(unexpectedDeathMessage, t);
                }
  
protected void processChildren(Container container, ClassLoader cl) {
            try {
                if (container.getLoader() != null) {
                    Thread.currentThread().setContextClassLoader
                        (container.getLoader().getClassLoader());
                }
                //这里container是StandardHost
                container.backgroundProcess();
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                log.error("Exception invoking periodic operation: ", t);
            } finally {
                Thread.currentThread().setContextClassLoader(cl);
            }
            Container[] children = container.findChildren();
            for (int i = 0; i < children.length; i++) {
                if (children[i].getBackgroundProcessorDelay() <= 0) {
                    processChildren(children[i], cl);
                }
            }
        }
    }

 StandardHost  方法可知 
backgroundProcess
 public void backgroundProcess() {
        
        if (!getState().isAvailable())
            return;

        if (cluster != null) {
            try {
                cluster.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e);                
            }
        }
        if (loader != null) {
            try {
                loader.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);                
            }
        }
        if (manager != null) {
            try {
                manager.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);                
            }
        }
        Realm realm = getRealmInternal();
        if (realm != null) {
            try {
                realm.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);                
            }
        }
        Valve current = pipeline.getFirst();
        while (current != null) {
            try {
                current.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);                
            }
            current = current.getNext();
        }
        fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
    }
 激活状态的   Lifecycle.PERIODIC_EVENT 代码如: fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null); 
此状态运行 我们在前面代码HostConfig中可以知道
 HostConfig中lifecycleEvent方法如下
 
    public void lifecycleEvent(LifecycleEvent event) {

        // Identify the host we are associated with
        try {
            host = (Host) event.getLifecycle();
            if (host instanceof StandardHost) {
                setCopyXML(((StandardHost) host).isCopyXML());
                setDeployXML(((StandardHost) host).isDeployXML());
                setUnpackWARs(((StandardHost) host).isUnpackWARs());
                setContextClass(((StandardHost) host).getContextClass());
            }
        } catch (ClassCastException e) {
            log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
            return;
        }

        // Process the event that has occurred
        if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
            check();
        } else if (event.getType().equals(Lifecycle.START_EVENT)) {
            start();
        } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
            stop();
        }
    }
 综上可以 tomcat定时的去扫描webapps目录下工程的变化
  • 大小: 18.3 KB
  • 大小: 135.9 KB
分享到:
评论

相关推荐

    tomcat9源码的eclipse工程

    【描述】"这是一个Eclipse的Tomcat源码工程,适合于查看Tomcat源码"意味着你可以通过Eclipse IDE高效地探索Tomcat的内部工作原理。Eclipse作为一款强大的Java开发工具,拥有优秀的代码导航、调试和重构功能,对于...

    tomcat6的源码

    源码中的`Host`和`Context`类展示了如何解析WAR文件并加载应用到服务器。 5. **JMX(Java Management Extensions)**:Tomcat支持JMX,允许管理员监控和管理服务器状态。查看`jmx`目录下的源码可以了解如何使用JMX...

    tomcat7源码下载

    一、Tomcat7源码结构解析 Tomcat7的源代码结构清晰,主要包含以下几个核心模块: 1. catalina:这是Tomcat的核心模块,负责处理Servlet容器的主要功能,如Servlet和Context的生命周期管理,请求处理等。 2. ...

    Tomcat深入剖析pdf+源码(Tomcat运行原理)

    7. **部署与热部署**:Tomcat支持自动部署和热部署,只需将WAR文件放入webapps目录,Tomcat会自动解压并部署应用。修改应用后,无需重启服务器,Tomcat可以检测到变化并自动更新。 8. **安全性**:Tomcat提供多种...

    Tomcat源码分析

    【标题】"Tomcat源码分析" 在深入探讨Tomcat源码之前,首先需要了解Tomcat是什么。Tomcat是一款开源的、基于Java的Web应用服务器,由Apache软件基金会开发。它实现了Java Servlet和JavaServer Pages(JSP)规范,...

    tomcat源码

    【Tomcat源码详解】 Tomcat,作为Apache...深入研究Tomcat源码,不仅能够帮助开发者理解Web服务器的工作原理,还能为优化应用性能、排查问题提供极大的便利。对于Java Web开发者而言,这是一个不可或缺的学习资源。

    tomcat8.0源码

    通过深入研究Apache Tomcat 8.0的源码,开发者可以了解Web服务器的工作原理,定制自己的容器,优化性能,甚至修复bug或开发新的功能。对于Java Web开发人员来说,这是一次宝贵的学习机会,有助于提升专业技能。

    Tomcat6源码下载

    总的来说,通过研究Tomcat 6.0的源码,我们可以深入理解Web服务器的工作原理,这对于开发高性能、高可用性的Web应用至关重要。同时,源码分析也能提升我们在遇到问题时的诊断和解决能力,为日常运维带来便利。因此,...

    apache-tomcat-8.5.100-src Tomcat源码解析

    总之,Apache Tomcat的源码解析是一次深入学习Java Web技术的宝贵机会,它可以帮助你更好地理解Servlet和JSP的运行机制,提升你的开发和调试技能。通过实际操作编译源码,你可以进一步掌握Maven和Java构建流程,为...

    tomcat源码编译

    **Tomcat源码编译详解** Tomcat,作为Apache软件基金会的一个开源项目,是Java Servlet、JavaServer Pages(JSP)以及Java Expression Language(EL)的实现,是世界上最流行的Java应用服务器之一。深入理解并编译...

    《深入剖析TOMCAT》中文版的源码

    深入学习Tomcat源码,有助于我们掌握以下关键知识点: 1. **Servlet生命周期**:理解Servlet的初始化、服务、销毁过程,以及Tomcat如何管理和调度Servlet实例。 2. **容器结构**:Tomcat的容器模型包括Engine...

    tomcat8源码的maven项目

    在这个项目中,开发者可能已经配置了相关的Maven插件和目标,以便于编译、测试和打包Tomcat源码。 【标签】: 1. **Tomcat8**:Tomcat 8是Tomcat服务器的第8个主要版本,它支持Java Servlet 3.1、JavaServer Pages...

    tomcat的源码

    二、Tomcat源码解析 1. **启动过程**:从`bin/catalina.sh`或`catalina.bat`开始,通过`Bootstrap`类启动`Catalina`,接着加载`Server.xml`配置,初始化各个组件。 2. **请求处理**:当请求到达时,Coyote连接器...

    tomcat9.0源码

    通过阅读和研究Tomcat 9.0.12的源码,开发者可以学习到如何设计和实现一个高效、可扩展的Web服务器,理解HTTP协议的处理流程,以及Java EE规范的实现细节。这对于提升Java服务器端开发能力非常有帮助。同时,源码也...

    2020面试说明Tomcat源码手写.rar

    在【压缩包子文件的文件名称列表】中,"Tomcat源码"很可能是包含了一系列文件,如Java源代码、配置文件、文档等,这些内容将帮助学习者逐步解析Tomcat的架构和工作流程。 以下是基于这些信息可能会涵盖的一些Tomcat...

    apache-tomcat-源码-lib包

    源码中,ClassLoader的实现(例如`org.apache.catalina.loader.WebappClassLoaderBase`)值得深入研究。 5. **部署和配置**:Tomcat支持多种方式部署Web应用,如WAR文件、目录结构或者通过管理接口。源码中,你可以...

    深入剖析Tomcat 随书 源码

    《深入剖析Tomcat》这本书是Java开发者们探索Tomcat服务器内部机制的重要参考资料,它带领读者逐步揭开Tomcat的...通过学习和研究Tomcat源码,我们可以提升技术水平,解决实际问题,甚至为Tomcat社区贡献自己的力量。

    tomcat3源码包

    《深入剖析Tomcat3:源码解析与运行机制》 Tomcat3作为Apache Tomcat的早期版本,虽然相比后来的6、7、8等版本在功能上显得较为简单,但正是这种简洁,使得它成为初学者研究Web服务器和Java Servlet容器理想的起点...

    tomcat7源码环境搭建

    4. **部署和生命周期管理**:了解Tomcat如何解析并部署WAR文件,以及Web应用的启动、停止和更新过程。 5. **安全管理**:Tomcat提供了多种安全特性,如角色基的安全认证,理解这些机制有助于构建更安全的Web服务。 ...

    tomcat及源码

    通过研究Tomcat源码,开发者可以了解到以下内容: 1. **线程模型**:了解Tomcat如何管理线程池,处理并发请求,以及如何在高负载下保持性能。 2. **请求处理流程**:从接收到HTTP请求到返回响应的整个过程,包括...

Global site tag (gtag.js) - Google Analytics