jetty之ContextHandler
来源:互联网 发布:seo站长工具查询 编辑:程序博客网 时间:2024/06/05 11:37
这篇文章要分析的类型是非常重要的一个类型...
ContextHandler,从名字上来看就是上下文的handler...
这里普及一下知识:每一个WebApp都对应相应一个context,那么也就对应一个contextHandler当servlet容器收到外部的http请求之后,会根据其请求的path信息来找到相应的webapplication来处理,也就是要找到对应的contextHandler来处理 ,这里也就知道了contextHandler的最重要的作用,那就是将属于当前web的http请求交由内部对应的servlet来处理。。。
由于这个类型的代码比较多,那么就不贴出所有的代码了。。。将其中一些重要的属性和方法抽出来分析一下就好了。。。(ContextHandler继承自HandlerWrapper)
首先来看一个线程变量的定义:
private static ThreadLocal __context=new ThreadLocal(); //当前的线程变量,用于保存到当前的servletContext
这个线程变量用于储存当前的servletContext,这个是在servlet标准中定义的接口,jetty中有自己的实现。。其定义就在ContextHandler类型中,一个内部类。。。
接下来是另外的属性定义:
protected SContext _scontext; //相应的servletcontext private AttributesMap _attributes; //属性, private AttributesMap _contextAttributes; //context的属性 private ClassLoader _classLoader; //用于加载app的class private String _contextPath="/"; //例如/manager什么的 private Map _initParams; //初始化参数 private String _displayName; private Resource _baseResource; //app部署的根目录 file:/C:/Users/js/AppData/Local/Temp/Jetty_127_0_0_1_80_manager.war__manager__.24ly2g/webapp/ private MimeTypes _mimeTypes; //文件类型对应 private Map _localeEncodingMap; private String[] _welcomeFiles; //首页的路径 private ErrorHandler _errorHandler; //错误handler private String[] _vhosts; //虚拟主机名 private Set _connectors; //其所用的connector private EventListener[] _eventListeners; private Logger _logger; private boolean _shutdown; private boolean _allowNullPathInfo; private int _maxFormContentSize=Integer.getInteger("org.mortbay.jetty.Request.maxFormContentSize",200000).intValue(); private boolean _compactPath=false; //一些lisntener的定义 private Object _contextListeners; //contextListener private Object _contextAttributeListeners; private Object _requestListeners; private Object _requestAttributeListeners; private Set _managedAttributes;
这里的scontext就是servlet的servlContext,contextPath是当前web的path,我们如果在servlet容器中启动多个app,那么每个webapplication的名字就是它的contextPath。。。。另外还有一些其他的属性,例如当前部署的根目录,一些初始化参数什么的。。。。
还有就是一些listener,例如contextListener什么的。。。
那么接下来我们来看看它的最重要的方法,handle方法:
//handle方法,用于处理远程的http请求,这里的target就是http请求的path,例如/manager/hello,这里其实是用于判断当前请求的path什么的,如果属于当前的webapp,那么进行处理 public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException { boolean new_context=false; SContext old_context=null; String old_context_path=null; String old_servlet_path=null; String old_path_info=null; ClassLoader old_classloader=null; Thread current_thread=null; //获取当前的http请求 Request base_request=(request instanceof Request)?(Request)request:HttpConnection.getCurrentConnection().getRequest(); if( !isStarted() || _shutdown || (dispatch==REQUEST && base_request.isHandled())) return; old_context=base_request.getContext(); //获取servletContext,这里一般情况下都是null,因为新建的socket连接发起的http请求 // Are we already in this context? if (old_context!=_scontext) { new_context=true; //如果有配置虚拟服务器名字,那么需要判断 if (_vhosts!=null && _vhosts.length>0) { String vhost = normalizeHostname( request.getServerName()); boolean match=false; // TODO non-linear lookup for (int i=0;!match && i<_vhosts.length;i++) { String contextVhost = _vhosts[i]; if(contextVhost==null) continue; if(contextVhost.startsWith("*.")) { // wildcard only at the beginning, and only for one additional subdomain level match=contextVhost.regionMatches(true,2,vhost,vhost.indexOf(".")+1,contextVhost.length()-2); } else match=contextVhost.equalsIgnoreCase(vhost); } if (!match) return; } //检查connector if (_connectors!=null && _connectors.size()>0) { String connector=HttpConnection.getCurrentConnection().getConnector().getName(); if (connector==null || !_connectors.contains(connector)) return; } // Nope - so check the target. if (dispatch==REQUEST) { if (_compactPath) { target=URIUtil.compactPath(target); } if (target.equals(_contextPath)){ //如果这里http请求的path等于contextPath,那么表示真正的pathinfo是空的,例如/manager,(启动多个app的话,会自动用app的名字来作为contextPath的前缀) if (!_allowNullPathInfo && !target.endsWith(URIUtil.SLASH)) { //判断是否运行空的path base_request.setHandled(true); if (request.getQueryString()!=null) response.sendRedirect(URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH)+"?"+request.getQueryString()); else response.sendRedirect(URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH)); return; } if (_contextPath.length()>1) { target=URIUtil.SLASH; request.setAttribute("org.mortbay.jetty.nullPathInfo",target); } } else if (target.startsWith(_contextPath) && (_contextPath.length()==1 || target.charAt(_contextPath.length())=='/')){ //这里看http的请求path是否已当前的contextPaht开始 if (_contextPath.length()>1) target=target.substring(_contextPath.length()); } else { //不是这个context该处理的,也就是不是这个webapplication该处理的 return; } } } try { old_context_path=base_request.getContextPath(); //这里一般是空,因为刚开始没有设置 old_servlet_path=base_request.getServletPath(); old_path_info=base_request.getPathInfo(); //设置servletContext base_request.setContext(_scontext); //为当前的http请求设置servletContext if (dispatch!=INCLUDE && target.startsWith("/")) { if (_contextPath.length()==1) base_request.setContextPath(""); else base_request.setContextPath(_contextPath); //设置contextPath base_request.setServletPath(null); base_request.setPathInfo(target); //设置pathInfo } ServletRequestEvent event=null; if (new_context) { // Set the classloader //设置当前的classLoader if (_classLoader!=null) { current_thread=Thread.currentThread(); old_classloader=current_thread.getContextClassLoader(); current_thread.setContextClassLoader(_classLoader); } // Handle the REALLY SILLY request events! if (_requestListeners!=null) { event = new ServletRequestEvent(_scontext,request); for(int i=0;i<LazyList.size(_requestListeners);i++) ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestInitialized(event); } //设置当前request的attributelistener for(int i=0;i<LazyList.size(_requestAttributeListeners);i++) base_request.addEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i))); } // Handle the request try { if (dispatch==REQUEST && isProtectedTarget(target)) //判断是否访问的是保护的资源,如果是的话,返回notfound,WEB-INF文件夹下面是保护资源 throw new HttpException(HttpServletResponse.SC_NOT_FOUND); //获取内部的handler来处理 Handler handler = getHandler(); //处理当前的http请求,这里其实是jetty.servlet.SessionHandler,不过最终还是调用ServletHandler if (handler!=null) handler.handle(target, request, response, dispatch); } catch(HttpException e) { Log.debug(e); response.sendError(e.getStatus(), e.getReason()); } finally { // Handle more REALLY SILLY request events! if (new_context) { for(int i=LazyList.size(_requestListeners);i-->0;) ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestDestroyed(event); for(int i=0;i<LazyList.size(_requestAttributeListeners);i++) base_request.removeEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i))); } } } finally { if (old_context!=_scontext) { // reset the classloader if (_classLoader!=null) { current_thread.setContextClassLoader(old_classloader); } // reset the context and servlet path. base_request.setContext(old_context); base_request.setContextPath(old_context_path); base_request.setServletPath(old_servlet_path); base_request.setPathInfo(old_path_info); } } }
这个方法就最终将会用于将http请求交给对应的servlet来处理。。。
这里的处理流程如下:
(1)判断当前的http请求的path与当前web程序的contextPath是否对应,如果不对应的话那么说明这个http请求不该由当前来处理。。。
(2)如果对应的话,那么设置当前这个request的servletContext,当前线程的classLoader等,
(3)调用内部的handler来处理这个request,这里一般情况下都是SessionHandler,不过SessionHandler其实最终也会调用ServletHandler来处理这个request,将其交给最终的servlet来处理。。。其实这也是jetty的链式调用的最重要利用。
(4)一些收尾的工作。。。。
好了,这里其实对整个ContextHandler的基本的一些了解就算差不多了。。。起码算是知道它用来干嘛的了。。至于说它的一些细节,就交给以后的运行分析再来说吧。。。
- jetty之ContextHandler
- Jetty之ContextHandler
- Jetty之ContextHandler
- Jetty源码分析之ContextHandler
- jetty之嵌入式运行jetty
- Jetty实战之 嵌入式运行Jetty
- Jetty实战之 嵌入式Jetty运行Servlet
- Jetty实战之 嵌入式Jetty运行Servlet
- Jetty实战之 嵌入式Jetty运行Servlet
- Jetty实战之 嵌入式运行Jetty
- Jetty实战之 嵌入式Jetty运行Servlet
- Jetty实战之 嵌入式Jetty运行Servlet
- Jetty实战之 嵌入式Jetty运行Servlet
- Jetty实战之 嵌入式运行Jetty
- Jetty实战之 嵌入式Jetty运行Servlet
- Jetty实战(1)之嵌入式运行Jetty
- Jetty实战之 嵌入式Jetty运行Servlet
- 嵌入式Jetty开发之代码启动Jetty
- JDK 7 环境配置 windows7_X64系统
- 文档在线预览方案
- C语言的那些事——函数部分(1)
- Apache的FileUpload用于Servlet与JSP环境下的文件上传
- PL/SQL工具优化配置(个性化设置)
- jetty之ContextHandler
- 哈夫曼编码
- C/C++文件输入输出操作——FILE*、fstream、windowsAPI
- SAP FICO基础(一)
- win7 安装超级终端
- C++中如何使用gsoap开发WebService
- lighttpd+php(fastcgi) 移植到arm-linux
- Win7下vs2010打包.net3.5
- servlet中的乱码问题