让Eclipse的TomcatPlugin支持Tomcat 8.x

Posted cao_xiaobo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了让Eclipse的TomcatPlugin支持Tomcat 8.x相关的知识,希望对你有一定的参考价值。

 使用tomcat插件启动项目的优势:

1.TomcatPlugin是一个免重启的开发插件,原始的Servers方式启动tomcat项目,修改xxx.ftl  或者 xxx.jsp 文件后需要重启tomcat后内容才能得到更新,而使用TomcatPlugin可以避免这种重复重启项目操作;

2.多项目同时启动时较方便。在开发环境中,可能要同时启动多个项目,而每一个平台都有一个独立的域名,使用Servers情况下,如果只使用一个8080端口启动多个项目,会有冲突。但是使用TomcatPlugin,只需要配置一下hosts文件就可以很方便的访问各个项目。

 

 

实现步骤:

1.下载eclipse tomcat 插件(略)

2.配置tomcat

tomcat插件下载完成后 Window-->Preperences 中找到tomcat配置项

 

 

 

3.配置server.xml

在conf/目录下找到server.xml文件,并在 Engine 标签中添加如下内容:

<Host name="www2.domain1.com"  appBase="webapps" unpackWARs="true" autoDeploy="true">
  <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />
  <Context path="" reloadable="true" docBase="项目目录1\\src\\main\\webapp" workDir="项目目录1\\work" >
      <Loader className="org.apache.catalina.loader.DevLoader" reloadable="true" debug="1" useSystemClassLoaderAsParent="false" />
  </Context>
</Host>
<Host name="www2.domain2.com"  appBase="webapps" unpackWARs="true" autoDeploy="true">
  <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />
  <Context path="" reloadable="true" docBase="项目目录2\\src\\main\\webapp" workDir="项目目录2\\work" >
      <Loader className="org.apache.catalina.loader.MyDevLoader" reloadable="true" debug="1" useSystemClassLoaderAsParent="false" />
  </Context>
</Host> 

 

 

 

4.配置hosts文件

在windows/system32/drivers/etc 目录下找到hosts文件,添加如下内容:

#	127.0.0.1       localhost
#	::1             localhost
127.0.0.1  	www2.domain1.com    www2.domain2.com    www2.domain3.com	

  

 

5.生成jar包

 

1.新建一个项目(或者使用原有的项目),创建一个包 名称为:org.apache.catalina.loader, 再创建一个类,名称为 MyDevLoader,拷贝下面java代码部分

备注:你可以随意创建一个包名和类名,但需要与 <Loader className="org.apache.catalina.loader.MyDevLoader" reloadable="true" debug="1" useSystemClassLoaderAsParent="false" /> 中的className保持一至即可。

2、消除编译报错的地方。主要是tomcat 中的lib目录下相关的jar包没有引入进来。

3、重新打成JAR包,命名DevloaderTomcat8.jar。

4、将这个jar文件放入tomcat 中的lib目录下。

 

package org.apache.catalina.loader;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import javax.servlet.ServletContext;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.loader.DevLoader.WebClassPathEntryHandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * @author caoxiaobo 备注:修改DevLoader源码后的,请生成jar包,然后放置tomcat中的lib目录下;
 */
public class MyDevLoader extends WebappLoader {
    private static final String info = "org.apache.catalina.loader.MyDevLoader/1.0";

    private String webClassPathFile = ".#webclasspath";
    private String tomcatPluginFile = ".tomcatplugin";

    WebappClassLoader loader = null;

    /**
     * @see org.apache.catalina.Lifecycle#start()
     *      如果您使用的是tomcat7,此处的方法名称为start(),如果是tomcat8,此处的方法名称为startInternal()
     */
    public void startInternal() throws LifecycleException {
        log("Starting MyDevLoader " + info);
        // setLoaderClass(DevWebappClassLoader.class.getName());

        // 如果是tomcat7,此处调用 start()方法,如果是tomcat8,此处调用startInternal()方法
        // super.start(); // tomcat7
        super.startInternal(); // tomcat8
        loader = (WebappClassLoader) super.getClassLoader();
        if (loader instanceof WebappClassLoader == false) {
            logError("Unable to install WebappClassLoader !");
            return;
        }

        List<String> webClassPathEntries = readWebClassPathEntries();
        StringBuffer classpath = new StringBuffer();
        for (Iterator<String> it = webClassPathEntries.iterator(); it.hasNext();) {
            String entry = (String) it.next();
            File f = new File(entry);
            if (f.exists()) {
                if (f.isDirectory() && entry.endsWith("/") == false)
                    f = new File(entry + "/");
                try {
                    URL url = f.toURI().toURL();
                    loader.addURL(url); // tomcat8
                    // loader.addRepository(url.toString()); // tomcat7
                    classpath.append(f.toString() + File.pathSeparatorChar);
                    log("added " + url.toString());
                } catch (MalformedURLException e) {
                    logError(entry + " invalid (MalformedURL)");
                }
            } else {
                logError(entry + " does not exist !");
            }
        }
        /*
         * try { devCl.loadClass("at.kase.webfaces.WebApplication");
         * devCl.loadClass("at.kase.taglib.BaseTag");
         * devCl.loadClass("at.kase.taglib.xhtml.XHTMLTag");
         * devCl.loadClass("at.kase.common.reflect.ClassHelper");
         * devCl.loadClass("javax.servlet.jsp.jstl.core.Config");
         * log("ALL OKAY !"); } catch(Exception e) { logError(e.toString()); }
         */
        String cp = (String) getServletContext().getAttribute(Globals.CLASS_PATH_ATTR);
        StringTokenizer tokenizer = new StringTokenizer(cp, File.pathSeparatorChar + "");
        while (tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken();
            // only on windows
            if (token.charAt(0) == \'/\' && token.charAt(2) == \':\')
                token = token.substring(1);
            classpath.append(token + File.pathSeparatorChar);
        }
        // cp = classpath + cp;
        getServletContext().setAttribute(Globals.CLASS_PATH_ATTR, classpath.toString());
        log("JSPCompiler Classpath = " + classpath);
    }

    private void log(String msg) {
        System.out.println("[MyDevLoader] " + msg);
    }

    private void logError(String msg) {
        System.err.println("[MyDevLoader] Error: " + msg);
    }

    private List<String> readWebClassPathEntries() {
        List<String> rc = null;

        File prjDir = getProjectRootDir();
        if (prjDir == null) {
            return new ArrayList<String>();
        }
        log("projectdir=" + prjDir.getAbsolutePath());

        // try loading tomcat plugin file
        // DON"T LOAD TOMCAT PLUGIN FILE (DOESN\'t HAVE FULL PATHS ANYMORE)
        rc = loadTomcatPluginFile(prjDir);

        if (rc == null) {
            //rc = loadWebClassPathFile(prjDir);
        }

        if (rc == null)
            rc = new ArrayList<String>(); // should not happen !
        return rc;
    }

    private File getProjectRootDir() {
        File rootDir = getWebappDir();
        FileFilter filter = new FileFilter() {
            public boolean accept(File file) {
                return (file.getName().equalsIgnoreCase(webClassPathFile)
                        || file.getName().equalsIgnoreCase(tomcatPluginFile));
            }
        };
        while (rootDir != null) {
            File[] files = rootDir.listFiles(filter);
            if (files != null && files.length >= 1) {
                return files[0].getParentFile();
            }
            rootDir = rootDir.getParentFile();
        }
        return null;
    }

    private List<String> loadWebClassPathFile(File prjDir) {
        File cpFile = new File(prjDir, webClassPathFile);
        if (cpFile.exists()) {
            FileReader reader = null;
            try {
                List<String> rc = new ArrayList<String>();
                reader = new FileReader(cpFile);
                LineNumberReader lr = new LineNumberReader(reader);
                String line = null;
                while ((line = lr.readLine()) != null) {
                    // convert \'\\\' to \'/\'
                    line = line.replace(\'\\\\\', \'/\');
                    rc.add(line);
                }
                return rc;
            } catch (IOException ioEx) {
                ioEx.printStackTrace();
                return null;
            } finally {
                try {
                    if (reader != null)
                        reader.close();
                } catch (Exception ignored) {
                }
            }
        } else {
            return null;
        }
    }

    private List<String> loadTomcatPluginFile(File prjDir) {
        File cpFile = new File(prjDir, tomcatPluginFile);
        if (!cpFile.exists()) {
            return null;
        }
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        SAXParser saxParser = null;
        try {
            saxParser = saxParserFactory.newSAXParser();
            // 仿照 Digester 类来实现xml解析
            WebClassPathEntryHandler dh = new WebClassPathEntryHandler();
            saxParser.parse(cpFile, dh);
            String[] jars = dh.getBodyText().toString().split(";");
            List<String> rc = new ArrayList<String>();
            for (String path : jars) {
                if (isNotBlank(path)) {
                    // 如果是编译后../classes 文件夹路径
                    if (!path.endsWith(".jar")) {
                        if (path.endsWith("/classes")) {
                            path = prjDir.getParentFile() + path;
                        }
                    }
                    rc.add(path);
                }
            }
            return rc;
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    private ServletContext getServletContext() {
        // return ((Context) getContainer()).getServletContext(); // tomcat7
        return super.getContext().getServletContext(); // tomcat8
    }

    private File getWebappDir() {
        File webAppDir = new File(getServletContext().getRealPath("/"));
        return webAppDir;
    }

    private static boolean isNotBlank(String str) {
        return null != str && !"".equals(str) && !"".equals(str.trim());
    }

    /**
     * 内部类,用来解析 .tomcatplugin 文件中的jar
     * 
     * @author Administrator
     *
     */
    private class WebClassPathEntryHandler extends DefaultHandler {

        private String localTag;
        private StringBuilder bodyText = new StringBuilder();

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            if (qName.equals("webClassPathEntry")) {
                localTag = "webClassPathEntry";
            }
        }

        @Override
        public void characters(char[] buffer, int start, int length) throws SAXException {
            if ("webClassPathEntry".equals(localTag)) {
                bodyText.append(buffer, start, length);
                bodyText.append(";");
            }

        }

        public StringBuilder getBodyText() {
            return bodyText;
        }

    }
}

 

特别提醒:这个类是加载你当前项目根目录下 .#webclasspath 或.tomcatplugin 文件的内容中的jar 文件的,有些项目没有这个文件,则需要从其它项目中拷贝一份出来放入你的项目根目录下。

 上面那个冗余代码比较多,下面这个示例为了更方便理解Tomcat 类的加载过程,我把它优化了一下:

package org.apache.catalina.loader;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.net.URL;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.catalina.LifecycleException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class DevLoader extends WebappLoader {

    /**
     * 通过 URLClassLoader 加载类/jar 文件
     */
    private static WebappClassLoader loader = null;

    private String webClassPathFileName = ".#webclasspath";
    private String tomcatPluginFileName = ".tomcatplugin";

    @Override
    protected void startInternal() throws LifecycleException {
        super.startInternal();
        // 仿照Digester获取ClassLoader的写法(Digester是用来解析xml文件的类)
        loader = (WebappClassLoader) super.getClassLoader();

        // 获取conf/context.xml中Context标签配置的 docBase路径
        String contextPath = this.getContext().getServletContext().getRealPath("/");
        System.out.println(contextPath);
        File rootDir = new File(contextPath);
        // 获取项目根路径
        FileFilter filter = new FileFilter() {
            public boolean accept(File file) {
                return (file.getName().equalsIgnoreCase(webClassPathFileName)
                        || file.getName().equalsIgnoreCase(tomcatPluginFileName));
            }
        };
        // 递归向上找父文件夹 
        while (rootDir != null) {
            File[] files = rootDir.listFiles(filter);
            if ((files != null) && (files.length >= 1)) {
                rootDir = files[0].getParentFile();
                break;
            } else {
                rootDir = rootDir.getParentFile();
            }
        }
        File webClassPathFile = new File(rootDir, webClassPathFileName);
        File tomcatPluginFile = new File(rootDir, tomcatPluginFileName);
        /**
         * 先加载 .#webclasspath 文件
         */
        if (webClassPathFile.exists()) {
            loadJars$WebClasspath(webClassPathFile);
            return;
        }
        if (tomcatPluginFile.exists()) {
            loadJars$TomcatPlugin(tomcatPluginFile, rootDir);
        }
    }

    /**
     * 加载jar文件 这里是解析.#webclasspath文件并加载jar文件
     */
    private void loadJars$WebClasspath(File webClassPathFile) {
        FileReader reader = null;
        LineNumberReader lr = null;
        try {
            reader = new FileReader(webClassPathFile);
            lr = new LineNumberReader(reader);
            String path = null;
            while ((path = lr.readLine()) != null) {
                if (isNotBlank(path)) {
                    path = path.replace(\'\\\\\', \'/\');
                    File file = new File(path);
                    URL url = file.toURI().toURL();                
                    loader.addURL(url);
                    System.out.println("[DevLoader]" + path);
                }
            }
        } catch (IOException ioEx) {
            ioEx.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null)
                    reader.close();
                if (lr != null)
                    lr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 加载jar文件 这里是解析.tomcatplugin文件并加载jar文件
     */
    private void loadJars$TomcatPlugin(File tomcatPluginFile, File rootDir) {

        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        SAXParser saxParser = null;
        try {
            saxParser = saxParserFactory.newSAXParser();
            // 仿照 Digester 类来实现xml解析
            WebClassPathEntryHandler dh = new WebClassPathEntryHandler();
            saxParser.parse(tomcatPluginFile, dh);
            String[] jars = dh.getBodyText().toString().split(";");
            for (String path : jars) {
                if (isNotBlank(path)) {
                    // 如果是编译后../classes 文件夹路径
                    if (!path.endsWith(".jar")) {
                        if (path.endsWith("/classes")) {
                            path = rootDir.getParentFile() + path;
                        }
                    } 
                    File f = new File(path.trim());
                    URL url = f.toURI().toURL();
                    loader.addURL(url);
                    System.out.println("[DevLoader]" + path);
                }
            }
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private static boolean isNotBlank(String str) {
        return null != str && !"".equals(str) && !"".equals(str.trim());
    }

    /**
     * 内部类,用来解析 .tomcatplugin 文件中的jar
     */
    class WebClassPathEntryHandler extends DefaultHandler {

        private String localTag;
        private StringBuilder bodyText = new StringBuilder();

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            if (qName.equals("webClassPathEntry")) {
                localTag = "webClassPathEntry";
            }
        }

        @Override
        public void characters(char[] buffer, int start, int length) throws SAXException {
            if ("webClassPathEntry".equals(localTag)) {
                bodyText.append(buffer, start, length);
                bodyText.append(";");
            }

        }

        public StringBuilder getBodyText() {
            return bodyText;
        }

    }

}

 

  

 

右键项目--> Properties --> Tomcat

 

至此我们已经配置完结了!

点击如下图标开始启动项目

 

 出现如下信息表示配置成功.

 

 

以上是关于让Eclipse的TomcatPlugin支持Tomcat 8.x的主要内容,如果未能解决你的问题,请参考以下文章

java开发之eclipse插件安装与配置(完)

Eclipse用Tomcat插件部署Java Web项目

Eclipse_插件_01_tomcat插件的安装

ssm 框架 -- eclipse4.6 安装插件 tomcat

搭建Eclipse开发环境

Eclipse