源码版本:Tomcat 8.0.41
Request和Response的门面模式

从UML图可以看到,Tomcat中HttpServletRequest和HttpServletResponse的实现类是org.apache.catalina.connector.Request和org.apache.catalina.connector.Response,但实际提供给Servlet的时候用的是门面类RequestFacade和ResponseFacade。这是因为实现类里面的public方法比接口的多,而且可能涉及到安全问题,如果Servlet直接将其强转成实现类,是可以访问这些方法的,存在安全问题,因为使用了门面模式,将这些方法隐藏起来。
统一日志消息处理
Tomcat8使用org.apache.catalina.tribes.util.StringManager对日志消息进行统一处理,每个包一般都有一个LocalStrings.properties文件,需要调用这些日志信息的类,会维护一个StringManager的实例,初始化时以当前包名为参数,以获取当前包对应的LocalStrings.properties文件:
private StringManager(String packageName);
private static final Hashtable<String, StringManager> managers =
new Hashtable<>();
/**
* Get the StringManager for a particular package. If a manager for
* a package already exists, it will be reused, else a new
* StringManager will be created and returned.
*
* @param packageName The package name
*/
public static final synchronized StringManager getManager(String packageName) {
StringManager mgr = managers.get(packageName);
if (mgr == null) {
mgr = new StringManager(packageName);
managers.put(packageName, mgr);
}
return mgr;
}
/* For Example */
protected static final StringManager sm = StringManager.getManager(Constants.Package);
可以看到它使用了Hashtable来维护每个包对应的StringManager单例。
然后在需要读取消息的时候调用StringManager的getString(String key)方法,如:
log.info(sm.getString("receiverBase.socket.bind", addr));
请求参数等的懒解析
为了提高效率,请求参数在第一次调用public String getParameter(String name)、public Enumeration<String> getParameterNames()等方法的时候才会解析,如果整个请求响应处理过程中都没有调用相关方法的话,请求参数将不会被解析,因为字符串处理的消耗不低。其他的一些属性也有类似的处理。主要的代码如下:
/**
* Request parameters parsed flag.
*/
protected boolean parametersParsed = false;
/**
* Return the value of the specified request parameter, if any; otherwise,
* return <code>null</code>. If there is more than one value defined,
* return only the first one.
*
* @param name Name of the desired request parameter
*/
@Override
public String getParameter(String name) {
if (!parametersParsed) {
parseParameters();
}
return coyoteRequest.getParameters().getParameter(name);
}
/**
* Returns a <code>Map</code> of the parameters of this request.
* Request parameters are extra information sent with the request.
* For HTTP servlets, parameters are contained in the query string
* or posted form data.
*
* @return A <code>Map</code> containing parameter names as keys
* and parameter values as map values.
*/
@Override
public Map<String, String[]> getParameterMap() {
if (parameterMap.isLocked()) {
return parameterMap;
}
Enumeration<String> enumeration = getParameterNames();
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement();
String[] values = getParameterValues(name);
parameterMap.put(name, values);
}
parameterMap.setLocked(true);
return parameterMap;
}
/**
* Return the names of all defined request parameters for this request.
*/
@Override
public Enumeration<String> getParameterNames() {
if (!parametersParsed) {
parseParameters();
}
return coyoteRequest.getParameters().getParameterNames();
}
/**
* Parse request parameters.
*/
protected void parseParameters() {
parametersParsed = true;
/*………具体的解析处理,在此省略………*/
}
其中ParameterMap是一个继承了LinkedHashMap的类:
public final class ParameterMap<K,V> extends LinkedHashMap<K,V>
Connector连接器
Tomcat8主要有四个Connector,分别为Http11Protocol、Http11NioProtocol、Http11Nio2Protocol、Http11AprProtocol,UML如上图所示,内容比较多,暂时不讨论了。
Tomcat容器层次
Tomcat中有四个层次的容器:
- Engine:整个Catalina Servlet引擎
- Host:包含一个或多个Context容器的虚拟主机
- Context:表示一个Web应用程序,包含一个或多个Wrapper
- Wrapper:表示一个独立的Servlet
以上四个类均实现了org.apache.catalina.Container接口,标准实现分别为org.apache.catalina.core包中的StandardEngine、StandardHost、StandardContext、StandardWrapper。

Pipeline管道
(尚未完工)
org.apache.catalina.valves.AccessLogValve
