让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
至此我们已经配置完结了!
点击如下图标开始启动项目
出现如下信息表示配置成功.