上一节中我们分析了通信的建立,既然建立了通信,那么当一个请求发送过来的时候,我们又是怎么去寻找到之前注册好的容器的呢?
connector.getService().getMapper().map(serverName, decodedURI,
version, request.getMappingData());
以上代码来自
org.apache.catalina.connector.CoyoteAdapter.postParseRequest(Request, Request, Response, Response)这个方法。可以看到tomcat调用Mapper的map去映射容器
//host是一个消息字节对象,内部维护的是host名
//uri 顾名思义,就是uri
//version 版本
//mappingData映射数据对象,这个类被Request关联,mappingData维护着寻找到的
//Host,Context
public void org.apache.catalina.mapper.Mapper.map(MessageBytes host, MessageBytes uri, String version,
MappingData mappingData) throws IOException {
if (host.isNull()) {
host.getCharChunk().append(defaultHostName);
}
host.toChars();
uri.toChars();
internalMap(host.getCharChunk(), uri.getCharChunk(), version,
mappingData);
}
internalMap方法就是具体的寻找容器方法
private final void internalMap(CharChunk host, CharChunk uri,
String version, MappingData mappingData) throws IOException {
。。。。。。省略部分代码
uri.setLimit(-1);
// Virtual host mapping
MappedHost[] hosts = this.hosts;
//忽略大小写精确匹配host,内部使用二分法查找
MappedHost mappedHost = exactFindIgnoreCase(hosts, host);
if (mappedHost == null) {
// Note: Internally, the Mapper does not use the leading * on a
// wildcard host. This is to allow this shortcut.
//如果host名是一个通配符开头的*.,那么寻找到第一个点,截取后再次进行精确匹配
int firstDot = host.indexOf('.');
if (firstDot > -1) {
int offset = host.getOffset();
try {
host.setOffset(firstDot + offset);
//精确匹配
mappedHost = exactFindIgnoreCase(hosts, host);
} finally {
// Make absolutely sure this gets reset
//恢复
host.setOffset(offset);
}
}
//如果还是没有找到,那么设置默认的host,如果连默认的host都没有,那么直接返回
if (mappedHost == null) {
mappedHost = defaultHost;
if (mappedHost == null) {
return;
}
}
}
//设置Host对象
mappingData.host = mappedHost.object;
// Context mapping
ContextList contextList = mappedHost.contextList;
MappedContext[] contexts = contextList.contexts;
//匹配context,匹配方式也是二分法查找,要么找到精确匹配的,要么就是仅次于当前uri路径的context
int pos = find(contexts, uri);
if (pos == -1) {
return;
}
int lastSlash = -1;
int uriEnd = uri.getEnd();
int length = -1;
boolean found = false;
MappedContext context = null;
while (pos >= 0) {
//获取匹配到的context
context = contexts[pos];
//如果uri路径是以context开头的
if (uri.startsWith(context.name)) {
length = context.name.length();
//长度一样,那好办,已经找到了
if (uri.getLength() == length) {
found = true;
break;
//如果context.name.length()后面紧跟的就是一个/,那么也表示寻找了
} else if (uri.startsWithIgnoreCase("/", length)) {
found = true;
break;
}
}
if (lastSlash == -1) {
//寻找contextList.nesting + 1次/,也就是找到第contextList.nesting个/的位置
//值得注意的是这个contextList.nesting是指这个集合中context路径最长的,tomcat从最后的/开始往前退
//直到找到匹配的context路径前缀,比如/test/a/b/c,其中只有一个context,它的路径是/test,那么就会从/test/a/b/c-》
///test/a/b/-》/test/a/-》/test/,当然如果还有个路径为/test/a的context,那么这个context优先被匹配
lastSlash = nthSlash(uri, contextList.nesting + 1);
} else {
//从后面往前找到最后一个/的位置
lastSlash = lastSlash(uri);
}
//将uri的messageByte的end设置到最后一个/的位置
uri.setEnd(lastSlash);
pos = find(contexts, uri);
}
//恢复原始的uri结束位置
uri.setEnd(uriEnd);
//如果没有找到,那就看看没有根路径的context,根路径的context如果有,一定是排在第一个位置
if (!found) {
if (contexts[0].name.equals("")) {
context = contexts[0];
} else {
context = null;
}
}
//没找到,直接返回
if (context == null) {
return;
}
//设置context路径
mappingData.contextPath.setString(context.name);
ContextVersion contextVersion = null;
//获取所有的版本
ContextVersion[] contextVersions = context.versions;
final int versionCount = contextVersions.length;
if (versionCount > 1) {
Context[] contextObjects = new Context[contextVersions.length];
for (int i = 0; i < contextObjects.length; i++) {
contextObjects[i] = contextVersions[i].object;
}
//给mappingData设置与之contextpath匹配的所有版本的context
mappingData.contexts = contextObjects;
if (version != null) {
//精确匹配版本,找到合适的context
contextVersion = exactFind(contextVersions, version);
}
}
//如果没有找到,那么就把最后一个版本,也就是最高版本返回
if (contextVersion == null) {
// Return the latest version
// The versions array is known to contain at least one element
contextVersion = contextVersions[versionCount - 1];
}
//设置context
mappingData.context = contextVersion.object;
//找到的context的/个数
mappingData.contextSlashCount = contextVersion.slashCount;
// Wrapper mapping
if (!contextVersion.isPaused()) {
//继续匹配wrapper
internalMapWrapper(contextVersion, uri, mappingData);
}
}
当host和context都找到之后,接下来要寻找的就是wrapper了
private final void org.apache.catalina.mapper.Mapper.internalMapWrapper(ContextVersion contextVersion,
CharChunk path,
MappingData mappingData) throws IOException {
int pathOffset = path.getOffset();
int pathEnd = path.getEnd();
boolean noServletPath = false;
//context路径长度
int length = contextVersion.path.length();
//如果和context路径一样长,那么就表示没有Servlet路径
if (length == (pathEnd - pathOffset)) {
noServletPath = true;
}
//servletPath的开始路径下标
int servletPath = pathOffset + length;
//设置偏移下标
path.setOffset(servletPath);
// Rule 1 -- Exact Match 精确匹配
MappedWrapper[] exactWrappers = contextVersion.exactWrappers;
//(*1*)
internalMapExactWrapper(exactWrappers, path, mappingData);
// Rule 2 -- Prefix Match 前缀匹配
boolean checkJspWelcomeFiles = false;
MappedWrapper[] wildcardWrappers = contextVersion.wildcardWrappers;
if (mappingData.wrapper == null) {
//(*2*)
internalMapWildcardWrapper(wildcardWrappers, contextVersion.nesting,
path, mappingData);
//如果是jsp通配符,并且是根路径,那么说明默认是jsp作为首页
if (mappingData.wrapper != null && mappingData.jspWildCard) {
char[] buf = path.getBuffer();
if (buf[pathEnd - 1] == '/') {
/*
* Path ending in '/' was mapped to JSP servlet based on
* wildcard match (e.g., as specified in url-pattern of a
* jsp-property-group.
* Force the context's welcome files, which are interpreted
* as JSP files (since they match the url-pattern), to be
* considered. See Bugzilla 27664.
*/
mappingData.wrapper = null;
checkJspWelcomeFiles = true;
} else {
// See Bugzilla 27704
mappingData.wrapperPath.setChars(buf, path.getStart(),
path.getLength());
mappingData.pathInfo.recycle();
}
}
}
if(mappingData.wrapper == null && noServletPath &&
contextVersion.object.getMapperContextRootRedirectEnabled()) {
// The path is empty, redirect to "/"
path.append('/');
pathEnd = path.getEnd();
mappingData.redirectPath.setChars
(path.getBuffer(), pathOffset, pathEnd - pathOffset);
path.setEnd(pathEnd - 1);
return;
}
// Rule 3 -- Extension Match 扩展名匹配
MappedWrapper[] extensionWrappers = contextVersion.extensionWrappers;
if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
//扩展名匹配
internalMapExtensionWrapper(extensionWrappers, path, mappingData,
true);
}
// Rule 4 -- Welcome resources processing for servlets
//当到这里还是没有找到任何wrapper的时候,就考虑使用欢迎页
if (mappingData.wrapper == null) {
boolean checkWelcomeFiles = checkJspWelcomeFiles;
if (!checkWelcomeFiles) {
char[] buf = path.getBuffer();
判断是否是以/结尾的,如果是,那么表示需要检查欢迎页
checkWelcomeFiles = (buf[pathEnd - 1] == '/');
}
if (checkWelcomeFiles) {
//循环遍历每个欢迎首页
for (int i = 0; (i < contextVersion.welcomeResources.length)
&& (mappingData.wrapper == null); i++) {
path.setOffset(pathOffset);
path.setEnd(pathEnd);
//补充获取欢迎页的路径
path.append(contextVersion.welcomeResources[i], 0,
contextVersion.welcomeResources[i].length());
path.setOffset(servletPath);
// Rule 4a -- Welcome resources processing for exact macth
//精确匹配wrapper
internalMapExactWrapper(exactWrappers, path, mappingData);
// Rule 4b -- Welcome resources processing for prefix match
//如果还是没有找到,那么就通过通配符查找
if (mappingData.wrapper == null) {
internalMapWildcardWrapper
(wildcardWrappers, contextVersion.nesting,
path, mappingData);
}
// Rule 4c -- Welcome resources processing
// for physical folder
//还是没有
if (mappingData.wrapper == null
&& contextVersion.resources != null) {
String pathStr = path.toString();
//查看是否存在这样的web资源
WebResource file =
contextVersion.resources.getResource(pathStr);
if (file != null && file.isFile()) {
//通过后缀匹配
internalMapExtensionWrapper(extensionWrappers, path,
mappingData, true);
//如果还是为空,那么就设置默认的wrapper
if (mappingData.wrapper == null
&& contextVersion.defaultWrapper != null) {
mappingData.wrapper =
contextVersion.defaultWrapper.object;
mappingData.requestPath.setChars
(path.getBuffer(), path.getStart(),
path.getLength());
mappingData.wrapperPath.setChars
(path.getBuffer(), path.getStart(),
path.getLength());
mappingData.requestPath.setString(pathStr);
mappingData.wrapperPath.setString(pathStr);
}
}
}
}
//恢复
path.setOffset(servletPath);
path.setEnd(pathEnd);
}
}
//后缀匹配,但是这个后缀匹配第四参数修改为了false,表示我不期望它是个物理资源
if (mappingData.wrapper == null) {
boolean checkWelcomeFiles = checkJspWelcomeFiles;
if (!checkWelcomeFiles) {
char[] buf = path.getBuffer();
checkWelcomeFiles = (buf[pathEnd - 1] == '/');
}
if (checkWelcomeFiles) {
for (int i = 0; (i < contextVersion.welcomeResources.length)
&& (mappingData.wrapper == null); i++) {
path.setOffset(pathOffset);
path.setEnd(pathEnd);
path.append(contextVersion.welcomeResources[i], 0,
contextVersion.welcomeResources[i].length());
path.setOffset(servletPath);
internalMapExtensionWrapper(extensionWrappers, path,
mappingData, false);
}
path.setOffset(servletPath);
path.setEnd(pathEnd);
}
}
// Rule 7 -- Default servlet
//默认Servlet
if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
//设置默认的wrapper
if (contextVersion.defaultWrapper != null) {
mappingData.wrapper = contextVersion.defaultWrapper.object;
mappingData.requestPath.setChars
(path.getBuffer(), path.getStart(), path.getLength());
mappingData.wrapperPath.setChars
(path.getBuffer(), path.getStart(), path.getLength());
mappingData.matchType = MappingMatch.DEFAULT;
}
// Redirection to a folder
char[] buf = path.getBuffer();
if (contextVersion.resources != null && buf[pathEnd -1 ] != '/') {
String pathStr = path.toString();
WebResource file;
// Handle context root
if (pathStr.length() == 0) {
file = contextVersion.resources.getResource("/");
} else {
file = contextVersion.resources.getResource(pathStr);
}
if (file != null && file.isDirectory() &&
contextVersion.object.getMapperDirectoryRedirectEnabled()) {
// Note: this mutates the path: do not do any processing
// after this (since we set the redirectPath, there
// shouldn't be any)
path.setOffset(pathOffset);
path.append('/');
mappingData.redirectPath.setChars
(path.getBuffer(), path.getStart(), path.getLength());
} else {
mappingData.requestPath.setString(pathStr);
mappingData.wrapperPath.setString(pathStr);
}
}
}
path.setOffset(pathOffset);
path.setEnd(pathEnd);
}
精确匹配
private final void org.apache.catalina.mapper.Mapper.internalMapExactWrapper
(MappedWrapper[] wrappers, CharChunk path, MappingData mappingData) {
//精确匹配
MappedWrapper wrapper = exactFind(wrappers, path);
if (wrapper != null) {
//设置Servlet路径
mappingData.requestPath.setString(wrapper.name);
mappingData.wrapper = wrapper.object;
//设置根路径类型
if (path.equals("/")) {
// Special handling for Context Root mapped servlet
mappingData.pathInfo.setString("/");
mappingData.wrapperPath.setString("");
// This seems wrong but it is what the spec says...
mappingData.contextPath.setString("");
mappingData.matchType = MappingMatch.CONTEXT_ROOT;
} else {
mappingData.wrapperPath.setString(wrapper.name);
//设置精确匹配
mappingData.matchType = MappingMatch.EXACT;
}
}
}
前缀匹配
private final void internalMapWildcardWrapper
(MappedWrapper[] wrappers, int nesting, CharChunk path,
MappingData mappingData) {
int pathEnd = path.getEnd();
int lastSlash = -1;
int length = -1;
//二分法查找
int pos = find(wrappers, path);
if (pos != -1) {
boolean found = false;
while (pos >= 0) {
if (path.startsWith(wrappers[pos].name)) {// /a/b/c /a/b/*(在包装wrapper的时候,这个/*会被去掉)
length = wrappers[pos].name.length();
//和匹配contex一样
if (path.getLength() == length) {
found = true;
break;
} else if (path.startsWithIgnoreCase("/", length)) {
found = true;
break;
}
}
if (lastSlash == -1) {
lastSlash = nthSlash(path, nesting + 1);//获取第nesting个/
} else {
lastSlash = lastSlash(path);//获取最后一个/
}
path.setEnd(lastSlash);
pos = find(wrappers, path);
}
//恢复
path.setEnd(pathEnd);
if (found) {
//设置路径
mappingData.wrapperPath.setString(wrappers[pos].name);
if (path.getLength() > length) {
//设置路径信息,*号通配符代表的路径
mappingData.pathInfo.setChars
(path.getBuffer(),
path.getOffset() + length,
path.getLength() - length);
}
//设置请求路径
mappingData.requestPath.setChars
(path.getBuffer(), path.getOffset(), path.getLength());
mappingData.wrapper = wrappers[pos].object;
mappingData.jspWildCard = wrappers[pos].jspWildCard;
mappingData.matchType = MappingMatch.PATH;
}
}
}
扩展名匹配
private final void org.apache.catalina.mapper.Mapper.internalMapExtensionWrapper(MappedWrapper[] wrappers,
CharChunk path, MappingData mappingData, boolean resourceExpected) {
//路径字符数组
char[] buf = path.getBuffer();
//路径最后一个位置
int pathEnd = path.getEnd();
//路径的开始偏移
int servletPath = path.getOffset();
int slash = -1;
for (int i = pathEnd - 1; i >= servletPath; i--) {
if (buf[i] == '/') {
//扎到最后一个/
slash = i;
break;
}
}
//从这个/的位置开始寻找后缀
if (slash >= 0) {
int period = -1;
for (int i = pathEnd - 1; i > slash; i--) {
if (buf[i] == '.') {
period = i;
break;
}
}
//如果找到后缀,进行后缀精确匹配
if (period >= 0) {
path.setOffset(period + 1);
path.setEnd(pathEnd);
MappedWrapper wrapper = exactFind(wrappers, path);
if (wrapper != null
&& (resourceExpected || !wrapper.resourceOnly)) {
//设置wrapper的路径
mappingData.wrapperPath.setChars(buf, servletPath, pathEnd
- servletPath);
//设置请求路径
mappingData.requestPath.setChars(buf, servletPath, pathEnd
- servletPath);
mappingData.wrapper = wrapper.object;
//匹配类型为扩展名匹配
mappingData.matchType = MappingMatch.EXTENSION;
}
//恢复偏移
path.setOffset(servletPath);
path.setEnd(pathEnd);
}
}
}
从上一节的一行代码中可以发现,tomcat是通过排管来进行执行的。首先执行的就是engine的排管,我们不管这个排管中有什么乱七八糟的管道阀,我们一定能够确定的是,engine内部一定有一个基础的管道阀,由于StandardEnginValve,StandardHostValve,StrandardContextValve没有做过多的逻辑,基本上都在判断是支持异步处理,这里我们只分析Wrapper的StandardWrapperValve
public final void invoke(Request request, Response response)
throws IOException, ServletException {
。。。。。。省略部分代码
// Allocate a servlet instance to process this request
try {
if (!unavailable) {
//获取servlet对象,如果已经创建直接获取(一般是那种onstartup大于零的在StandardContext启动的时候就进行了创建)
//调用其初始化方法
servlet = wrapper.allocate();
}
} catch (UnavailableException e) {
。。。。。。省略
}
//获取请求路径消息字节
MessageBytes requestPathMB = request.getRequestPathMB();
//请求分发类型
DispatcherType dispatcherType = DispatcherType.REQUEST;
//如果支持的是异步分发类型,那么是指分发类型为异步
if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC;
request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
requestPathMB);
// Create the filter chain for this request
//创建过滤器链
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
// Call the filter chain for this request
// NOTE: This also calls the servlet's service() method
try {
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
//这个getSwallowOutput方法的作用,从代码来看是用于捕获线程的输出使用的
//在finally块中捕获的日志通过日志打印了
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) {
//异步处理
request.getAsyncContextInternal().doInternalDispatch();
} else {
//调用过滤器链
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
context.getLogger().info(log);
}
}
} else {
//异步处理
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
//调用过滤器链
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}
}
} catch (ClientAbortException e) {
。。。。。。省略
}
// Release the filter chain (if any) for this request
if (filterChain != null) {
//释放链条,将链条引用置空,servlet置空
filterChain.release();
}
// Deallocate the allocated servlet instance
try {
if (servlet != null) {
//servlet计数减一,并把当前servlet设置到servlet池子中
wrapper.deallocate(servlet);
}
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.deallocateException",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}
// If this servlet has been marked permanently unavailable,
// unload it and release this instance
try {
if ((servlet != null) &&
(wrapper.getAvailable() == Long.MAX_VALUE)) {
//销毁servlet
wrapper.unload();
}
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.unloadException",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}
long t2=System.currentTimeMillis();
long time=t2-t1;
processingTime += time;
if( time > maxTime) maxTime=time;
if( time < minTime) minTime=time;
}
异步处理是servlet3.0新增的,无法就是将操作的方式从同步变成了异步,然后保持长连接即可(我个人理解),所以这里就不进行额外的分析了,我们直接分析过滤链吧
public static ApplicationFilterChain org.apache.catalina.core.ApplicationFilterFactory.createFilterChain(ServletRequest request,
Wrapper wrapper, Servlet servlet) {
// If there is no servlet to execute, return null
if (servlet == null)
return null;
// Create and initialize a filter chain object
ApplicationFilterChain filterChain = null;
if (request instanceof Request) {
Request req = (Request) request;
if (Globals.IS_SECURITY_ENABLED) {
// Security: Do not recycle
filterChain = new ApplicationFilterChain();
} else {
//从缓存中获取,如果没有就创建一个
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} else {
// Request dispatcher in use
filterChain = new ApplicationFilterChain();
}
//设置servlet
filterChain.setServlet(servlet);
//设置是否支持异步
filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());
// Acquire the filter mappings for this Context
//父容器
StandardContext context = (StandardContext) wrapper.getParent();
//获取过滤器FilterMap,维护这mapping与过滤器的关系
FilterMap filterMaps[] = context.findFilterMaps();
// If there are no filter mappings, we are done
//如果没有过滤器,那啥也不用干了,真爽
if ((filterMaps == null) || (filterMaps.length == 0))
return (filterChain);
// Acquire the information we will need to match filter mappings
//获取请求分发类型
DispatcherType dispatcher =
(DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);
String requestPath = null;
//获取请求路径
Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
if (attribute != null){
requestPath = attribute.toString();
}
//获取servlet名字
String servletName = wrapper.getName();
// Add the relevant path-mapped filters to this filter chain
for (int i = 0; i < filterMaps.length; i++) {
//匹配请求分发类型,我们在配置filter的时候如果没有指定,那么默认是REQUEST类型
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
//匹配url,也分为精确匹配,前缀匹配(也就是后缀通配符为/*的),扩展名匹配
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
//从context中找到对应的过滤器配置对象
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
//添加
filterChain.addFilter(filterConfig);
}
// Add filters that match on servlet name second
//通过servlet的名字进行匹配
for (int i = 0; i < filterMaps.length; i++) {
//匹配分发类型
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
//匹配servlet的名字,如果过滤器配置是*,那么表示匹配所有
if (!matchFiltersServlet(filterMaps[i], servletName))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
// Return the completed filter chain
return filterChain;
}
现在我们已经准备好了所有适用于当前servlet的过滤器,那么我们就来看下这个链条是怎么驱动的。
void org.apache.catalina.core.ApplicationFilterChain.addFilter(ApplicationFilterConfig filterConfig) {
// Prevent the same filter being added multiple times
//如果已经添加了,那么不允许再次添加
for(ApplicationFilterConfig filter:filters)
if(filter==filterConfig)
return;
//拷贝
if (n == filters.length) {
ApplicationFilterConfig[] newFilters =
new ApplicationFilterConfig[n + INCREMENT];
System.arraycopy(filters, 0, newFilters, 0, n);
filters = newFilters;
}
//添加到数组后面
filters[n++] = filterConfig;
}
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
//如果开启了JDK的安全管理,那么需要通过这种调用方式获取最高权限,不被安全拦截
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
try {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Void>() {
@Override
public Void run()
throws ServletException, IOException {
internalDoFilter(req,res);
return null;
}
}
);
} catch( PrivilegedActionException pe) {
。。。。。。省略
}
} else {
internalDoFilter(request,response);
}
}
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
//pos表示当前将要调用的filter的下标
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
//如果request要求是异步支持,但是过滤却不支持,那么就设置为不支持异步
if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
//是否开启了JDK的安全管理器
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
//通过安全管理器的方式调用,这种调用方式是为了获取最高权限,防止jdk的安全拦截
SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
} else {
//调用过滤器的doFilter方法,驱动链条调用。
filter.doFilter(request, response, this);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}
// We fell off the end of the chain -- call the servlet instance
try {
//将request与response设置到当前线程中
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}
//判断是否支持异步请求
if (request.isAsyncSupported() && !servletSupportsAsync) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
// Use potentially wrapped request from this point
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse) &&
Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
//安全管理的方式调用,这种调用方式是为了获取最高权限,防止jdk的安全拦截
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args,
principal);
} else {
//调用servlet的service方法
servlet.service(request, response);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.servlet"), e);
} finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(null);
lastServicedResponse.set(null);
}
}
}
现在我们终于看到了servlet的service方法,我们在实现一个servlet的时候,一般不会覆盖servlet的service方法,那到底是为什么呢?
public void javax.servlet.http.HttpServlet.service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取请求方法
String method = req.getMethod();
//get
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
ifModifiedSince = -1;
}
//比较,查看是否已经过期,如果过期,重新响应
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
//如果没有过期,那么直接返回304
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
//head
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
//post
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
//put
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
//delete
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
//options
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
//trace
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//不支持的请求方法
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
好了,到此,tomcat的分析就结束了。至于session的管理,以后有时间在来写个番外吧,哈哈,我这么懒,谁知道什么时候呢?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?