1.前言
最近在項目中有一個想法,要是項目中能通過網頁熱部署一些二次開發的模塊,那應該是一件很有意思而且很有實際作用的功能。所以想到了Tomcat中類加載器中反委派機制做法。爲了更深入瞭解tomcat類加載器的反委派機制的具體實現,需要搭建Tomcat源碼環境。雖然不是很難,但是還有避免不了一些坑,依次記載,方便大家學習交流。
2.環境準備
2.1 Idea環境
本次Idea版本採用比較穩定的IntelliJIDEA2018.2.1。
2.2 JDK版本
JDK版本爲1.8.0.131_x64。
2.3 Tomcat版本
本次tomcat版本採用tomcat7.0.103。可以通過在官網下載。注意,此處應該選擇Source Code Distributions。下載的格式爲zip。
https://tomcat.apache.org/download-70.cgi
3.源碼部署
3.1 解壓zip壓縮包,此處簡單,一句帶過。
3.2 通過idea導入此項目
依次選擇【Open -->選擇剛纔解壓的文件夾】。
3.3 指定jdk,工程語言級別以及編譯輸出路徑
3.4 指定src以及test路徑
將java指定爲【Sources Root】,將test指定爲【Test Sources Root】,具體操作如下:
3.5 引入Jar包
此時,我們發現有部分代碼飄紅,說明需要引入部分jar包,如下圖。
爲了方便大家構建項目,這裏我們通過maven將依賴的jar包引導到工程中去。下文是我整理好的pom.xml文件。
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.surpass</groupId>
<artifactId>tomcat</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>tomcat</name>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.10.7</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core</artifactId>
<version>3.20.0</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxrpc</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jmock</groupId>
<artifactId>jmock</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.jmock</groupId>
<artifactId>jmock</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.4.2</version>
</dependency>
</dependencies>
</project>
3.5.1 將pom.xml文件拷貝到tomcat的文件夾下。
3.5.2 編程maven工程,引入pom.xml文件
選擇idea右側的選項卡【Maven Projects】,然後點擊【+】,現在剛纔拷貝進去的pom.xml文件,在彈出的點擊【import changes】,此操作對於熟悉idea的讀者並不陌生,可以直接略過。
此時,我們發現之前飄紅的已經消失了。
3.6 運行tomcat啓動文件
我們通過路徑找到類文件org.apache.catalina.startup.Bootstrap。熟悉idea的朋友知道,雙擊shift鍵,輸入Bootstrap可以快速定位。接下來我們運行此類。很不幸,發現缺少一個類。
通過此類分析,這個類並沒有在import導入,所以我們猜想這個CookieFilter類應該和TestCookieFilter在同一個全類路徑,即在util包下。爲了方便大家學習,我也把這個文件分享出來,然後把此類放到${tomcat}\test\util下。
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package util;
import java.util.Locale;
import java.util.StringTokenizer;
/**
* Processes a cookie header and attempts to obfuscate any cookie values that
* represent session IDs from other web applications. Since session cookie names
* are configurable, as are session ID lengths, this filter is not expected to
* be 100% effective.
*
* It is required that the examples web application is removed in security
* conscious environments as documented in the Security How-To. This filter is
* intended to reduce the impact of failing to follow that advice. A failure by
* this filter to obfuscate a session ID or similar value is not a security
* vulnerability. In such instances the vulnerability is the failure to remove
* the examples web application.
*/
public class CookieFilter {
private static final String OBFUSCATED = "[obfuscated]";
private CookieFilter() {
// Hide default constructor
}
public static String filter(String cookieHeader, String sessionId) {
StringBuilder sb = new StringBuilder(cookieHeader.length());
// Cookie name value pairs are ';' separated.
// Session IDs don't use ; in the value so don't worry about quoted
// values that contain ;
StringTokenizer st = new StringTokenizer(cookieHeader, ";");
boolean first = true;
while (st.hasMoreTokens()) {
if (first) {
first = false;
} else {
sb.append(';');
}
sb.append(filterNameValuePair(st.nextToken(), sessionId));
}
return sb.toString();
}
private static String filterNameValuePair(String input, String sessionId) {
int i = input.indexOf('=');
if (i == -1) {
return input;
}
String name = input.substring(0, i);
String value = input.substring(i + 1, input.length());
return name + "=" + filter(name, value, sessionId);
}
public static String filter(String cookieName, String cookieValue, String sessionId) {
if (cookieName.toLowerCase(Locale.ENGLISH).contains("jsessionid") &&
(sessionId == null || !cookieValue.contains(sessionId))) {
cookieValue = OBFUSCATED;
}
return cookieValue;
}
}
3.7 運行tomcat啓動文件
此時我們在運行此類,發現運行成功。隨後我們在網頁打開http://127.0.0.1:8080驗證是否啓動成功。
4 修改亂碼
不知道上面讀者是否發現在輸出日誌的控制檯中發生了亂碼。
其實解決問題的思路很簡單,我們需要修改兩個類。
4.1 org.apache.tomcat.util.res.StringManager
代碼如插入位置如下圖
try{
value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
}catch (Exception e){}
4.2 org.apache.jasper.compiler.Localizer
代碼如插入位置如下圖
try{
errMsg = new String(errMsg.getBytes("ISO-8859-1"),"UTF-8");
}catch (Exception e){}
4.3 此時我們再次運行,發現亂碼不見了。