设为首页 收藏本站
查看: 626|回复: 0

[经验分享] 浅析Tomcat之StandardWrapperValve的Servlet请求处理

[复制链接]

尚未签到

发表于 2017-2-8 11:10:50 | 显示全部楼层 |阅读模式
StandardWrapper代表的是一个Servlet,那么它也就是容器调用栈中的最终点.Http请求到达后进行的处理也不单单只是调用了Servlet的方法.它还经过了一层的过滤器.它对外服务与上层容器类似,也是调用了基础阀的方法.那么所有这些操作也是在StandardWrapperValve这个阀中发生的.
首先看下StandardWrapperValve的invoke方法.下面是简要抽出的方法实现.

public final void invoke(Request request, Response response)  
throws IOException, ServletException {  
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;  
}  
servlet = wrapper.allocate();  
// Create the filter chain for this request  
ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();  
ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper, servlet);  
filterChain.doFilter(request.getRequest(), response.getResponse());  
// 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();  
}  
}  
wrapper.deallocate(servlet);  
// If this servlet has been marked permanently unavailable,  
// unload it and release this instance  
if ((servlet != null) && (wrapper.getAvailable() == Long.MAX_VALUE)) {  
wrapper.unload();  
}  
}  
 这个方法主要的流程是先确认Context是否是可使用的,如果可以使用的话就allocate一个servlet ,然后用他们创建一个ApplicationFilterChain,接着调用doFilter方法. 最后进行ApplicationFilterChain的回收利用,和servlet的deallocate及wrapper的unload就此结束请求.上面的方法似乎也没有对Servlet的service方法的调用.其实不然且看下面分析.

public ApplicationFilterChain createFilterChain  
(ServletRequest request, Wrapper wrapper, Servlet servlet) {  
.....  
filterChain.setServlet(servlet);  
// 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 ,dispatcher)) {  
continue;  
}  
if (!matchFiltersURL(filterMaps, requestPath))  
continue;  
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)  
context.findFilterConfig(filterMaps.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 ,dispatcher)) {  
continue;  
}  
if (!matchFiltersServlet(filterMaps, servletName))  
continue;  
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)  
context.findFilterConfig(filterMaps.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);  
}  
 从上面的代码中我们可以看出createFilterChain构造出了一个过滤器和Servlet的集合体那就是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>() {  
@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 {  
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.doFilter(request, response, this);  
}  
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,  
filter, request, response);  
} catch (....) {  
if (filter != null)  
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,  
filter, request, response, e);  
throw 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 {  
servlet.service(request, response);  
}  
} else {  
servlet.service(request, response);  
}  
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,  
servlet, request, response);  
} catch (....) {  
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,  
servlet, request, response, e);  
throw e;  
} finally {  
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {  
lastServicedRequest.set(null);  
lastServicedResponse.set(null);  
}  
}  
}  
   上述代码中我们可以看出来doFilter调用了内部的一个私有方法.该方法就是对filter进行逐个调用,触法其生命周期事件.最后调用了Servlet的service方法.Service方法后面发生了什么,作为一个web开发者应该都很清楚.至此,请求处理结束.所有的内容都是以Response返回的.
 
首发于泛泛之辈 - http://www.lihongkun.com/archives/159

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-339186-1-1.html 上篇帖子: 浅析Tomcat之Coyote连接器架构分析 下篇帖子: Tomcat重启后让session依然存在
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表