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

[Tomcat6.0源码]请求的处理四Pipeline、Valve、FilterChain

2012-09-27 11:29 375 查看
CoyoteAdapter.service()中调用postParseRequest对请求进行封装,匹配相关的Host、Context、Wrapper等。接着执行:

connector.getContainer().getPipeline().getFirst().invoke(request, response);

程序将按Connector(N-1)Engine(1-N)Host(1-N)Context(1-N)Wrapper这种顺序执行下去。

connector.getContainer()返回StandardEngine对象,这在Connector实例化的时候赋值的。

connector.getContainer().getPipeline()既是StandardEngine.getPipeline(),StandardEngine继承ContainerBase,ContainerBase在属性中创建StandardPipeline对象。

传入的参数是StandardEngine对象,将保存在StandardPipeline.container属性中。

protected Pipeline pipeline = new StandardPipeline(this);

connector.getContainer().getPipeline().getFirst()既是执行StandardPipeline.getFirst():

public Valve getFirst() {
if (first != null) {
return first;
} else {
return basic;
}
}

取不到first就取basic,这个是什么时候赋值的?StandardEngine的构造方法:

/**
* Create a new StandardEngine component with the default basic Valve.
*/
public StandardEngine() {

super();
pipeline.setBasic(new StandardEngineValve());
/* Set the jmvRoute using the system property jvmRoute */
try {
setJvmRoute(System.getProperty("jvmRoute"));
} catch(Exception ex) {
}
// By default, the engine will hold the reloading thread
backgroundProcessorDelay = 10;

}

那么StandardPipeline.getFirst()返回的就是StandardEngineValve()对象。而

connector.getContainer().getPipeline().getFirst().invoke(request, response);

执行的就是StandardEngineValve.invoke():

public final void invoke(Request request, Response response)
throws IOException, ServletException {

// Select the Host to be used for this Request
Host host = request.getHost();
if (host == null) {
response.sendError
(HttpServletResponse.SC_BAD_REQUEST,
sm.getString("standardEngine.noHost",
request.getServerName()));
return;
}

// Ask this Host to process this request
host.getPipeline().getFirst().invoke(request, response);

}

request.getHost()是在CoyoteAdapter.postParseRequest()解析request的时候设置好的。host.getPipeline().getFirst().invoke(request, response);调用过程和前面的类似,既是执行StandardHostValve.invoke():

public final void invoke(Request request, Response response)
throws IOException, ServletException {

// Select the Context to be used for this Request
Context context = request.getContext();
if (context == null) {
response.sendError
(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
sm.getString("standardHost.noContext"));
return;
}

// Bind the context CL to the current thread
if( context.getLoader() != null ) {
// Not started - it should check for availability first
// This should eventually move to Engine, it's generic.
Thread.currentThread().setContextClassLoader
(context.getLoader().getClassLoader());
}

// Ask this Context to process this request
context.getPipeline().getFirst().invoke(request, response);

// Access a session (if present) to update last accessed time, based on a
// strict interpretation of the specification
if (Globals.STRICT_SERVLET_COMPLIANCE) {
request.getSession(false);
}

// Error page processing
response.setSuspended(false);

Throwable t = (Throwable) request.getAttribute(Globals.EXCEPTION_ATTR);

if (t != null) {
throwable(request, response, t);
} else {
status(request, response);
}

// Restore the context classloader
Thread.currentThread().setContextClassLoader
(StandardHostValve.class.getClassLoader());

}

同样context.getPipeline().getFirst().invoke(request, response);既是执行StandardContextValve.invoke():

public final void invoke(Request request, Response response)
throws IOException, ServletException {

// Disallow any direct access to resources under WEB-INF or META-INF
MessageBytes requestPathMB = request.getRequestPathMB();
if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
|| (requestPathMB.equalsIgnoreCase("/META-INF"))
|| (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
|| (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
notFound(response);
return;
}

// Wait if we are reloading
boolean reloaded = false;
while (context.getPaused()) {
reloaded = true;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
;
}
}

// Reloading will have stopped the old webappclassloader and
// created a new one
if (reloaded &&
context.getLoader() != null &&
context.getLoader().getClassLoader() != null) {
Thread.currentThread().setContextClassLoader(
context.getLoader().getClassLoader());
}

// Select the Wrapper to be used for this Request
Wrapper wrapper = request.getWrapper();
if (wrapper == null) {
notFound(response);
return;
} else if (wrapper.isUnavailable()) {
// May be as a result of a reload, try and find the new wrapper
wrapper = (Wrapper) container.findChild(wrapper.getName());
if (wrapper == null) {
notFound(response);
return;
}
}

// Normal request processing
Object instances[] = context.getApplicationEventListeners();

ServletRequestEvent event = null;

if ((instances != null)
&& (instances.length > 0)) {
event = new ServletRequestEvent
(((StandardContext) container).getServletContext(),
request.getRequest());
// create pre-service event
for (int i = 0; i < instances.length; i++) {
if (instances[i] == null)
continue;
if (!(instances[i] instanceof ServletRequestListener))
continue;
ServletRequestListener listener =
(ServletRequestListener) instances[i];
try {
listener.requestInitialized(event);
} catch (Throwable t) {
container.getLogger().error(sm.getString("standardContext.requestListener.requestInit",
instances[i].getClass().getName()), t);
ServletRequest sreq = request.getRequest();
sreq.setAttribute(Globals.EXCEPTION_ATTR,t);
return;
}
}
}

wrapper.getPipeline().getFirst().invoke(request, response);

if ((instances !=null ) &&
(instances.length > 0)) {
// create post-service event
for (int i = 0; i < instances.length; i++) {
if (instances[i] == null)
continue;
if (!(instances[i] instanceof ServletRequestListener))
continue;
ServletRequestListener listener =
(ServletRequestListener) instances[i];
try {
listener.requestDestroyed(event);
} catch (Throwable t) {
container.getLogger().error(sm.getString("standardContext.requestListener.requestDestroy",
instances[i].getClass().getName()), t);
ServletRequest sreq = request.getRequest();
sreq.setAttribute(Globals.EXCEPTION_ATTR,t);
}
}
}

}

wrapper.getPipeline().getFirst().invoke(request, response);执行StandardWrapperValve.invoke(),经过设置参数后,需要取出StandardWrapper对象中相关联的Servlet:

// Allocate a servlet instance to process this request
try {
if (!unavailable) {
servlet = wrapper.allocate();
}
} catch (UnavailableException e) {......}

wrapper.allocate() 返回的是StandardWrapper.instance属性。那这个instance是什么时候赋值的?

回到StandardWrapper的上一级组件StandardContext启动时候,StandardContext.start():

// Load and initialize all "load on startup" servlets
if (ok) {
loadOnStartup(findChildren());
}

findChildren()返回注册到Context.children中的StandardWrapper,这种使用HashMap的方式到是可以看看:

public Container[] findChildren() {

synchronized (children) {
Container results[] = new Container[children.size()];
return ((Container[]) children.values().toArray(results));
}

}

StandardContext.loadOnStartup():

/**
* Load and initialize all servlets marked "load on startup" in the
* web application deployment descriptor.
*
* @param children Array of wrappers for all currently defined
*  servlets (including those not declared load on startup)
*/
public void loadOnStartup(Container children[]) {

// Collect "load on startup" servlets that need to be initialized
TreeMap map = new TreeMap();
for (int i = 0; i < children.length; i++) {
Wrapper wrapper = (Wrapper) children[i];
int loadOnStartup = wrapper.getLoadOnStartup();
if (loadOnStartup < 0)
continue;
Integer key = Integer.valueOf(loadOnStartup);
ArrayList list = (ArrayList) map.get(key);
if (list == null) {
list = new ArrayList();
map.put(key, list);
}
list.add(wrapper);
}

// Load the collected "load on startup" servlets
Iterator keys = map.keySet().iterator();
while (keys.hasNext()) {
Integer key = (Integer) keys.next();
ArrayList list = (ArrayList) map.get(key);
Iterator wrappers = list.iterator();
while (wrappers.hasNext()) {
Wrapper wrapper = (Wrapper) wrappers.next();
try {
wrapper.load();
} catch (ServletException e) {
getLogger().error(sm.getString("standardWrapper.loadException",
getName()), StandardWrapper.getRootCause(e));
// NOTE: load errors (including a servlet that throws
// UnavailableException from tht init() method) are NOT
// fatal to application startup
}
}
}

}

wrapper.load()既是StandardWrapper.load():

public synchronized void load() throws ServletException {
instance = loadServlet();
}

调用loadServlet()方法为StandardWrapper的instance属性创建一个Servlet:

servlet = (Servlet) classClass.newInstance();

classClass来自web.xml文件中的:

<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/helloServlet</url-pattern>
</servlet-mapping>

经过WebRuleSet的规则解析:

digester.addCallMethod(prefix + "web-app/servlet/servlet-class",
"setServletClass", 0);
digester.addCallMethod(prefix + "web-app/servlet/servlet-name",
"setName", 0);

将对classClass的来源变量StandardWrapper.servletClass进行赋值。

StandardWrapperValve.invoke()中的servlet已经查到源头了,这个servlet就是最终处理业务的servlet。我们知道执行servlet前会一层层的先执行过滤器,越来越接近水面。

// Create the filter chain for this request
ApplicationFilterFactory factory =
ApplicationFilterFactory.getInstance();
ApplicationFilterChain filterChain =
factory.createFilterChain(request, wrapper, servlet);

ApplicationFilterFactory.createFilterChain():

/**
* Construct and return a FilterChain implementation that will wrap the
* execution of the specified servlet instance.  If we should not execute
* a filter chain at all, return <code>null</code>.
*
* @param request The servlet request we are processing
* @param servlet The servlet instance to be wrapped
*/
public ApplicationFilterChain createFilterChain
(ServletRequest request, Wrapper wrapper, Servlet servlet) {

// get the dispatcher type
int dispatcher = -1;
if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
Integer dispatcherInt =
(Integer) request.getAttribute(DISPATCHER_TYPE_ATTR);
dispatcher = dispatcherInt.intValue();
}
String requestPath = null;
Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);

if (attribute != null){
requestPath = attribute.toString();
}

HttpServletRequest hreq = null;
if (request instanceof HttpServletRequest)
hreq = (HttpServletRequest)request;
// 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.setServlet(servlet);

filterChain.setSupport
(((StandardWrapper)wrapper).getInstanceSupport());

// Acquire the filter mappings for this Context
StandardContext context = (StandardContext) wrapper.getParent();
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;
}
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
}
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;
}
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);

}

先new出一个filterChain,再filterChain.setServlet(servlet);再取过滤器:

// Acquire the filter mappings for this Context
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();

Context实例化的时候,ContextConfig.applicationWebConfig()解析WebRuleSet类中配置规则,实例化Filter添加到StandardContext的filterMap中。

digester.addObjectCreate(prefix + "web-app/filter-mapping",
"org.apache.catalina.deploy.FilterMap");
digester.addSetNext(prefix + "web-app/filter-mapping",
"addFilterMap",
"org.apache.catalina.deploy.FilterMap");

先匹配符合路径的过滤器,再匹配符合类名的过滤器,将添加到filterChain.addFilter(filterConfig);

接下来就是执行过滤器了:

filterChain.doFilter
(request.getRequest(), response.getResponse());

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() {
public Object 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);
}
}

ApplicationFilterChain.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( 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);
}

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 (Globals.STRICT_SERVLET_COMPLIANCE) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}

support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,
servlet, request, response);
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((HttpServletRequest) request,
(HttpServletResponse) 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) {
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response, e);
throw new ServletException
(sm.getString("filterChain.servlet"), e);
} finally {
if (Globals.STRICT_SERVLET_COMPLIANCE) {
lastServicedRequest.set(null);
lastServicedResponse.set(null);
}
}

}

filter.doFilter(request, response, this);当filter数组中还有过滤器的时候,就创建过滤器,并调用它:

filter.doFilter(request, response, this);

这个就到了我们平时写的filter了,filter实现Filter接口,其doFilter中必须有一行,filterChain.doFilter(request, response);这个filterChain就是上边调用的this。

这样的话,只要没有执行完所有的过滤器,就会不断的创建过滤器,一直调用执行。

过滤器执行完后,会执行:

servlet.service((HttpServletRequest) request,
(HttpServletResponse) response);

我们编写的servlet一般继承至HttpServlet,servlet.service()既是执行HttpServlet.service():

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

String method = req.getMethod();

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

判断请求的方法,到了我们熟悉的doPost()、doGet()了,这两个方法在业务Servlet中我们一般会重写,处理业务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: