前言
- tomcat 在web开发中的地位举足轻重,本文就对tomcat8 进行源码运行,使用的os是 mac10,jdk8
准备工作
- tomcat源码下载地址: https://tomcat.apache.org/download-80.cgi
- idea工具: https://www.jetbrains.com/idea/download
- maven: http://maven.apache.org/download.cgi
- jdk 这里用8的版本
解压后的项目结构
配置工作
1. 解压完后在本地建立catalina-home(文件名称自定义即可,路径也自定义即可,一些文章介绍的是固定名称和路径的,大可不必)
2. 将tomcat解压中的conf 和webapps复制一份到 第一步中的catalina-home中(这两步不配置也是可以运行起来的,只是自定义一些配置方便调试)
3. 在tomcat根目录下创建pom.xml(位置见上述项目结构,这个就不多做解释,J2EE maven管理包是日常操作了),pom中的配置如下:
此配置是报错调试了几次之后的结果,如果你用的不同版本可能会遇到不同的问题,所以为了降低学习成本,尽量同一环境配置
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.tomcat</groupId>
<artifactId>Tomcat8.5</artifactId>
<name>Tomcat8.5</name>
<version>8.5</version>
<build>
<finalName>Tomcat8.0</finalName>
<!-- 指定源文件为java 、test -->
<sourceDirectory>java</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<resources>
<resource>
<directory>java</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>test</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3</version>
<configuration>
<encoding>UTF-8</encoding>
<!-- 指定jdk 编译 版本 -->
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<!-- 添加tomcat8 所需jar包依赖 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxrpc</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.6.1</version>
</dependency>
<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
4. 到这里配置就差不多完成了,可以配置以下VM参数(路径根据自己前边的步骤来定)
-Dcatalina.home=/Users/user/project/study/catalina-home
-Dcatalina.base=/Users/user/project/study/catalina-home
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=/Users/user/project/study/catalina-home/conf/logging.properties
5. 启动tomcat (tomcat启动入口在 org.apache.catalina.startup.Bootstrap#main)
5.1 问题1:启动乱码
这个问题在网上看了很多解决方案,但是都没有生效,最终根据源码debug,发现两个地方出来的字符串是乱码的
- org.apache.jasper.compiler.Localizer#getMessage(java.lang.String) 这里 errMsg是乱码的,这里自己加下转码代码如下:
public static String getMessage(String errCode) {
String errMsg = errCode;
try {
if (bundle != null) {
errMsg = bundle.getString(errCode);
//这里自己转下编码
try {
errMsg = new String(errMsg.getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
} catch (MissingResourceException e) {
}
return errMsg;
}
- 第二个地方: org.apache.tomcat.util.res.StringManager#getString(java.lang.String)
public String getString(String key) {
if (key == null){
String msg = "key may not have a null value";
throw new IllegalArgumentException(msg);
}
String str = null;
try {
// Avoid NPE if bundle is null and treat it like an MRE
if (bundle != null) {
str = bundle.getString(key);
}
} catch (MissingResourceException mre) {
//bad: shouldn't mask an exception the following way:
// str = "[cannot find message associated with key '" + key +
// "' due to " + mre + "]";
// because it hides the fact that the String was missing
// from the calling code.
//good: could just throw the exception (or wrap it in another)
// but that would probably cause much havoc on existing
// code.
//better: consistent with container pattern to
// simply return null. Calling code can then do
// a null check.
str = null;
}
//这里处理下编码问题
try {
str = new String(str.getBytes("ISO-8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return str;
}
PS:网上有很多人写的文章是org.apache.tomcat.util.res.StringManager类中的getString(final String key, final Object... args)方法 这里处理编码问题,这里其实不彻底,他底层调用的还是
org.apache.tomcat.util.res.StringManager#getString(java.lang.String),只是修复了其中一条路,其他case还是会乱码,当然tomcat修改配置文件可以解决这些问题,不过修改代码更直接快速
5.2 处理好这些后 重新运行tomcat并访问 http://localhost:8080
这是因为tomcat启动的时候没有初始化jsp解析器,需要在 org.apache.catalina.startup.ContextConfig#configureStart 加入以下代码(该方法内必定会执行的任意行即可,比如第一行):
context.addServletContainerInitializer(new JasperInitializer(), null);