您的位置:首页 > 运维架构 > Tomcat

tomcat原理解析(七):执行servlet

2017-06-07 17:15 525 查看

一  概述

       前面章节已经说到http的请求到达了管道处理。最后的一个管道是StandardWrapper中的管道,它最后的阀门是StandardWrapperValve,阀门中的invoke代码主要做了两件事情:1.执行过滤器链,2调用http请求servlet的service方法。

二 调用过滤器并执行servlet

这里再次贴下invoke中的代码,部分省略掉:

@Override
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();//取当前阀门对应的wrapper容器
Servlet servlet = null;
Context context = (Context) wrapper.getParent();//取wrapper容器对应的父context容器

// Check for the application being marked unavailable
if (!context.getAvailable()) {
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardContext.isUnavailable"));
unavailable = true;
}

// Check for the servlet being marked unavailable
//检查servlet被标记不可用
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) {
//加载wrapper对应的servlet实例来处理此请求
//通过java反射机制来加载对象
servlet = wrapper.allocate();
}
} catch (UnavailableException e) {

} catch (ServletException e) {

} catch (Throwable e) {

}

// Identify if the request is Comet related now that the servlet has been allocated
boolean comet = false;
if (servlet instanceof CometProcessor
&& request.getAttribute("org.apache.tomcat.comet.support") == Boolean.TRUE) {
comet = true;
request.setComet(true);
}

// Acknowledge the request
try {
response.sendAcknowledgement();
} catch (IOException e) {

} catch (Throwable e) {

}
MessageBytes requestPathMB = request.getRequestPathMB();
DispatcherType dispatcherType = DispatcherType.REQUEST;
if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC;
request.setAttribute
(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
dispatcherType);
request.setAttribute
(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
requestPathMB);
// Create the filter chain for this request
ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();//创建过滤器链工厂对象是单列的
//创建一个过滤器链对象,里面循环加载了配置中的过滤器对象
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 {
String jspFile = wrapper.getJspFile();
if (jspFile != null)
request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
else
request.removeAttribute(Globals.JSP_FILE_ATTR);
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) {
//TODO SERVLET3 - async
((AsyncContextImpl)request.getAsyncContext()).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()) {
//TODO SERVLET3 - async
((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();
} else if (comet) {
request.setComet(true);
filterChain.doFilterEvent(request.getEvent());
} else {
//采用递归循环执行过滤器链中的过滤器配置,并通过反射机制加载过滤器类
filterChain.doFilter(request.getRequest(), response.getResponse());
}
}

}
request.removeAttribute(Globals.JSP_FILE_ATTR);
} catch (ClientAbortException e) {

} catch (IOException e) {

} catch (UnavailableException e) {

} catch (ServletException e) {

} catch (Throwable 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) {

}

// 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) {

}
long t2=System.currentTimeMillis();

long time=t2-t1;
processingTime += time;
if( time > maxTime) maxTime=time;
if( time < minTime) minTime=time;

}

上面的代码主要做了两件事
1.取当前阀门对应的wrapper容器,我们知道wrapper容器是对一个servlet信息的封装
2.创建单例的ApplicationFilterFactory对象
3.创建过滤器链ApplicationFilterChain对象
4.调用ApplicationFilterChain的doFilter方法,以递归的方式循环执行过滤器链中的过滤器

跟进到ApplicationFilterChain类的doFilter方法,代码如下:

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>() {
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 {
internalDoFilter(request,response);
}
}


doFilter方法中主要调用了internalDoFilter方法,代码如下:

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);

args = null;
} else {
filter.doFilter(request, response, this);//递归调用过滤器链中的Filter
}

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) {
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);
args = null;
} else {
servlet.service(request, response);//执行http请求对应的servlet的servie方法
}
} else {
servlet.service(request, response);//执行http请求对应的servlet的servie方法
}
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response);
} catch (IOException e) {

} catch (ServletException e) {

} catch (RuntimeException e) {

} catch (Throwable e) {

} finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(null);
lastServicedResponse.set(null);
}
}

}


internalDoFilter方法中主要干了两件事情

1.递归执行过滤器链中的过滤器
2.执行完过滤器以后,执行servlet的service方法

因为所有的servlet对象都继承HttpServlet类,跟到HttpServlet类的service方法代码如下:
@Override
public void 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);
}
}
查看最后一行service(request, response);调用了当前HttpServlet类的另外一个service方法在参数类型上存在差别。

protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {

String method = req.getMethod();//取当前请求的方法名如get post

//根据http请求的方法名判断是小于post方法还是get方法
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}

} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);

} else if (method.equals(METHOD_POST)) {
doPost(req, resp);

} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);

} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);

} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);

} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);

} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//

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);
}
}


service方法中主要是根据请求对象(HttpServletRequest)拿到是调用的get方法和post方法。我们跟进到get方法中的代码如下:
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
doGet方法中只有返回405,400异常处理的代码,这是为什么呢?
因为我们自己开发写的servlet类都会继承HttpServlet对象,同时会重写doGet和doPost方法。所以在HttpServlet的service方法中调用的doGet方法其实执行的是HttpServlet子类中的doGe方法。

三 总结

         在web开发中我们定义的servlet最终都是实现了servlet接口,servlet接口是连接tomcat容器和web应用的规范。   试着扩展想想struts,springmvc应该也是实现servlet接口才会正常在tomcat中部署使用。
  到这里从浏览器发起http请求到如何定位并执行对应的servlet主流程已经结束,个人感觉只是知道了tomat的主体流程,很多细节的代码没有完全理解,不知道这样的阅读理解层次算不算掌握了tomcat的实现原理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tomcat