tomcat组件结构图
一次http请求处理的debug调用栈
相关源码
/** StandardWrapperValve.java */
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// Initialize local variables we may need
boolean unavailable = false;
Throwable throwable = null;
// This should be a Request attribute...
long t1=System.currentTimeMillis();
requestCount++;
StandardWrapper wrapper = (StandardWrapper) getContainer();
Servlet servlet = null;
Context context = (Context) wrapper.getParent();
// Check for the application being marked unavailable
if (!context.getState().isAvailable()) {
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardContext.isUnavailable"));
unavailable = true;
}
// Check for the servlet being marked unavailable
if (!unavailable && wrapper.isUnavailable()) {
container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
unavailable = true;
}
// Allocate a servlet instance to process this request
try {
if (!unavailable) {
// 实例化且初始化处理请求的servlet
servlet = wrapper.allocate();
}
} catch (UnavailableException e) {
container.getLogger().error(
sm.getString("standardWrapper.allocateException",
wrapper.getName()), e);
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
} catch (ServletException e) {
container.getLogger().error(sm.getString("standardWrapper.allocateException",
wrapper.getName()), StandardWrapper.getRootCause(e));
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.allocateException",
wrapper.getName()), e);
throwable = e;
exception(request, response, e);
servlet = null;
}
// Identify if the request is Comet related now that the servlet has been allocated
boolean comet = false;
if (servlet instanceof CometProcessor && Boolean.TRUE.equals(request.getAttribute(
Globals.COMET_SUPPORTED_ATTR))) {
comet = true;
request.setComet(true);
}
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
ApplicationFilterFactory factory =
ApplicationFilterFactory.getInstance();
// 创建filter调用链
ApplicationFilterChain filterChain =
factory.createFilterChain(request, wrapper, servlet);
// Reset comet flag value after creating the filter chain
request.setComet(false);
// 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
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else if (comet) {
filterChain.doFilterEvent(request.getEvent());
request.setComet(true);
} 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 if (comet) {
request.setComet(true);
filterChain.doFilterEvent(request.getEvent());
} else {
// 处理http请求,调用filter链,且完成servlet调用
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}
}
} catch (ClientAbortException e) {
throwable = e;
exception(request, response, e);
} catch (IOException e) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
throwable = e;
exception(request, response, e);
} catch (UnavailableException e) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
// throwable = e;
// exception(request, response, e);
wrapper.unavailable(e);
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
// Do not save exception in 'throwable', because we
// do not want to do exception(request, response, e) processing
} catch (ServletException e) {
Throwable rootCause = StandardWrapper.getRootCause(e);
if (!(rootCause instanceof ClientAbortException)) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceExceptionRoot",
wrapper.getName(), context.getName(), e.getMessage()),
rootCause);
}
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
throwable = e;
exception(request, response, e);
}
// Release the filter chain (if any) for this request
if (filterChain != null) {
if (request.isComet()) {
// If this is a Comet request, then the same chain will be used for the
// processing of all subsequent events.
filterChain.reuse();
} else {
filterChain.release();
}
}
// Deallocate the allocated servlet instance
try {
if (servlet != null) {
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)) {
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;
}
/** StandardWrapper.java */
public Servlet allocate() throws ServletException {
// If we are currently unloading this servlet, throw an exception
if (unloading) {
throw new ServletException(sm.getString("standardWrapper.unloading", getName()));
}
boolean newInstance = false;
// If not SingleThreadedModel, return the same instance every time
if (!singleThreadModel) {
// Load and initialize our instance if necessary
if (instance == null || !instanceInitialized) {
synchronized (this) {
if (instance == null) {
try {
if (log.isDebugEnabled()) {
log.debug("Allocating non-STM instance");
}
// Note: We don't know if the Servlet implements
// SingleThreadModel until we have loaded it.
instance = loadServlet();
newInstance = true;
if (!singleThreadModel) {
// For non-STM, increment here to prevent a race
// condition with unload. Bug 43683, test case
// #3
countAllocated.incrementAndGet();
}
} catch (ServletException e) {
throw e;
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("standardWrapper.allocate"), e);
}
}
if (!instanceInitialized) {
initServlet(instance);
}
}
}
if (singleThreadModel) {
if (newInstance) {
// Have to do this outside of the sync above to prevent a
// possible deadlock
synchronized (instancePool) {
instancePool.push(instance);
nInstances++;
}
}
} else {
if (log.isTraceEnabled()) {
log.trace(" Returning non-STM instance");
}
// For new instances, count will have been incremented at the
// time of creation
if (!newInstance) {
countAllocated.incrementAndGet();
}
return instance;
}
}
synchronized (instancePool) {
while (countAllocated.get() >= nInstances) {
// Allocate a new instance if possible, or else wait
if (nInstances < maxInstances) {
try {
instancePool.push(loadServlet());
nInstances++;
} catch (ServletException e) {
throw e;
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("standardWrapper.allocate"), e);
}
} else {
try {
instancePool.wait();
} catch (InterruptedException e) {
// Ignore
}
}
}
if (log.isTraceEnabled()) {
log.trace(" Returning allocated STM instance");
}
countAllocated.incrementAndGet();
return instancePool.pop();
}
}
// 实例化且初始化servlet
public synchronized Servlet loadServlet() throws ServletException {
if (unloading) {
throw new ServletException(
sm.getString("standardWrapper.unloading", getName()));
}
// Nothing to do if we already have an instance or an instance pool
if (!singleThreadModel && (instance != null))
return instance;
PrintStream out = System.out;
if (swallowOutput) {
SystemLogHandler.startCapture();
}
Servlet servlet;
try {
long t1=System.currentTimeMillis();
// Complain if no servlet class has been specified
if (servletClass == null) {
unavailable(null);
throw new ServletException
(sm.getString("standardWrapper.notClass", getName()));
}
InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager();
try {
// 实例化servlet
servlet = (Servlet) instanceManager.newInstance(servletClass);
} catch (ClassCastException e) {
unavailable(null);
// Restore the context ClassLoader
throw new ServletException
(sm.getString("standardWrapper.notServlet", servletClass), e);
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
unavailable(null);
// Added extra log statement for Bugzilla 36630:
// http://bz.apache.org/bugzilla/show_bug.cgi?id=36630
if(log.isDebugEnabled()) {
log.debug(sm.getString("standardWrapper.instantiate", servletClass), e);
}
// Restore the context ClassLoader
throw new ServletException
(sm.getString("standardWrapper.instantiate", servletClass), e);
}
if (multipartConfigElement == null) {
MultipartConfig annotation =
servlet.getClass().getAnnotation(MultipartConfig.class);
if (annotation != null) {
multipartConfigElement =
new MultipartConfigElement(annotation);
}
}
processServletSecurityAnnotation(servlet.getClass());
// Special handling for ContainerServlet instances
if ((servlet instanceof ContainerServlet) &&
(isContainerProvidedServlet(servletClass) ||
((Context) getParent()).getPrivileged() )) {
((ContainerServlet) servlet).setWrapper(this);
}
classLoadTime=(int) (System.currentTimeMillis() -t1);
if (servlet instanceof SingleThreadModel) {
if (instancePool == null) {
instancePool = new Stack<Servlet>();
}
singleThreadModel = true;
}
// 初始化servlet
initServlet(servlet);
fireContainerEvent("load", this);
loadTime=System.currentTimeMillis() -t1;
} finally {
if (swallowOutput) {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
if (getServletContext() != null) {
getServletContext().log(log);
} else {
out.println(log);
}
}
}
}
return servlet;
}
/** ApplicationFilterFactory.java */
// 创建filter调用链
public ApplicationFilterChain createFilterChain
(ServletRequest request, Wrapper wrapper, Servlet servlet) {
// get the dispatcher type
DispatcherType dispatcher = null;
if (request.getAttribute(Globals.DISPATCHER_TYPE_ATTR) != null) {
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();
}
// If there is no servlet to execute, return null
if (servlet == null)
return (null);
boolean comet = false;
// Create and initialize a filter chain object
ApplicationFilterChain filterChain = null;
if (request instanceof Request) {
Request req = (Request) request;
comet = req.isComet();
if (Globals.IS_SECURITY_ENABLED) {
// Security: Do not recycle
filterChain = new ApplicationFilterChain();
if (comet) {
req.setFilterChain(filterChain);
}
} else {
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} else {
// Request dispatcher in use
filterChain = new ApplicationFilterChain();
}
// filterChain关联servlet
filterChain.setServlet(servlet);
filterChain.setSupport
(((StandardWrapper)wrapper).getInstanceSupport());
// Acquire the filter mappings for this Context
StandardContext context = (StandardContext) wrapper.getParent();
// 获取context配置所有的filter
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
String servletName = wrapper.getName();
// Add the relevant path-mapped filters to this filter chain
for (int i = 0; i < filterMaps.length; i++) {
// 转发类型匹配
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
// URL匹配
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
boolean isCometFilter = false;
if (comet) {
try {
isCometFilter = filterConfig.getFilter() instanceof CometFilter;
} catch (Exception e) {
// Note: The try catch is there because getFilter has a lot of
// declared exceptions. However, the filter is allocated much
// earlier
Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(t);
}
if (isCometFilter) {
filterChain.addFilter(filterConfig);
}
} else {
filterChain.addFilter(filterConfig);
}
}
// Add filters that match on servlet name second
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;
}
boolean isCometFilter = false;
if (comet) {
try {
isCometFilter = filterConfig.getFilter() instanceof CometFilter;
} catch (Exception e) {
// Note: The try catch is there because getFilter has a lot of
// declared exceptions. However, the filter is allocated much
// earlier
}
if (isCometFilter) {
filterChain.addFilter(filterConfig);
}
} else {
filterChain.addFilter(filterConfig);
}
}
// Return the completed filter chain
return (filterChain);
}
/** ApplicationFilterChain.java */
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
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) {
Exception e = pe.getException();
if (e instanceof ServletException)
throw (ServletException) e;
else if (e instanceof IOException)
throw (IOException) e;
else if (e instanceof RuntimeException)
throw (RuntimeException) e;
else
throw new ServletException(e.getMessage(), e);
}
} else {
//实际调用filter链
internalDoFilter(request,response);
}
}
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = null;
try {
filter = filterConfig.getFilter();
support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
filter, request, response);
if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
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};
SecurityUtil.doAsPrivilege
("doFilter", filter, classType, args, principal);
} else {
// 顺序调用filter链
filter.doFilter(request, response, this);
}
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response);
} catch (IOException e) {
if (filter != null)
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response, e);
throw e;
} catch (ServletException e) {
if (filter != null)
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response, e);
throw e;
} catch (RuntimeException e) {
if (filter != null)
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response, e);
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
if (filter != null)
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response, e);
throw new ServletException
(sm.getString("filterChain.filter"), e);
}
return;
}
// We fell off the end of the chain -- call the servlet instance
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}
support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,
servlet, request, response);
if (request.isAsyncSupported()
&& !support.getWrapper().isAsyncSupported()) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
// Use potentially wrapped request from this point
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse)) {
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args,
principal);
} else {
// filter链调用完成后,完成servlet调用
servlet.service(request, response);
}
} else {
servlet.service(request, response);
}
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response);
} catch (IOException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response, e);
throw e;
} catch (ServletException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response, e);
throw e;
} catch (RuntimeException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response, e);
throw e;
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response, e);
throw new ServletException
(sm.getString("filterChain.servlet"), e);
} finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(null);
lastServicedResponse.set(null);
}
}
}