前面很多文章都提到过ServletHandler这种类型,它在整个http的处理中所占的位置如下:
(1)connector -> (2)server->(3)contextHandlerCollection->(4)WebAppContext->(5)ServletHandler->(6)Servlet
从上面整个http的处理过程来看,ServletHandler应该算得上是最接近用户定义的servlet的了。。。
一般情况下context收到http请求之后,这个请求最终都会直接交到servletHandler来处理,因此它也需要负责对http请求的path进行处理,从而才能将这个http请求交给正确的servlet。。。。
好了,先来看看ServletHandler的一些重要的属性的定义吧:
private ContextHandler _contextHandler; //这个servlet所属的contextHandler
private ContextHandler.SContext _servletContext; //当前这个context的servletcontext
private FilterHolder[] _filters; //filter数组
private FilterMapping[] _filterMappings; //xml中的filter的map信息
private boolean _filterChainsCached=true;
private int _maxFilterChainsCacheSize=1000;
private boolean _startWithUnavailable=true;
private ServletHolder[] _servlets; //servletholder数组,一般情况下用户定义的servlet都会被servletholder包装一下
private ServletMapping[] _servletMappings; //用于保存从xml中读取出来的servlet的map信息
private transient Map _filterNameMap= new HashMap(); //filter的name对应
private transient List _filterPathMappings; //将filter与特定的path对应起来
private transient MultiMap _filterNameMappings; //servlet的name与filter的对应,有的filter可能会指定特定的servlet
private transient Map _servletNameMap=new HashMap(); //servlet与名字进行对应
private transient PathMap _servletPathMap; //pathmap,这个很重要,当请求来了之后,就会通过它来匹配出合适的servlet来处理
protected transient HashMap _chainCache[]; //请求访问path与fitlerchain的缓存,防止每次都要创建
这里最为重要的一个属性应该就是servletPathMap了吧,我们在web.xml文件中会定义许多servlet,最后都会通过 <servlet-mapping> 元素将某个servlet与一个或者多个path对应起来。。。而这最终的对应关系都会在servletPathMap里面。。。另外还有许多其他的属性,具体他们是干什么的,应该注释就说的很清楚了吧。。。
那么接下来我们来看看ServletHandler的doStart方法吧:
//servlethandler的启动过程
protected synchronized void doStart()
throws Exception {
_servletContext=ContextHandler.getCurrentContext(); //获取当前的servletcontext
_contextHandler=_servletContext==null?null:_servletContext.getContextHandler(); //保存其所属的contextHandler
updateNameMappings(); //名字对应map的更新,也就是我们在xml文件中定义的servlet名字与servletholder对象的对应,当然这里还有filter
updateMappings(); //处理xml文件中定义的mapping信息,这里最重要要做的事情就是更新pathMap
if(_filterChainsCached) //这个数组的构建比较奇怪啊
_chainCache= new HashMap[]{null,new HashMap(),new HashMap(),null,new HashMap(),null,null,null,new HashMap()};
super.doStart();
if (_contextHandler==null || !(_contextHandler instanceof Context)) {//一般情况下不会调用,除非直接在server的handler就弄成了ServletHandr,在context的start后会在外面调用init方法
initialize(); //这个方法用于从classLoader里面载入servlet的calss文件,并且需要的话,会初始化这个servlet对象
}
}
代码还算比较的简洁吧,因为要做的事情都调用其他的方法来处理了,这里主要就是要建立两个map,首先是name与filterHolder或者servletHolder的对应关系,接着是path与fitler或者servlet的对应关系。。。。
那么先来看看updateNameMappings方法吧:
//更新与名字关联的map,filter的namemap与servlet的namemap
protected synchronized void updateNameMappings() {
_filterNameMap.clear(); //清空filter的name关联map
if (_filters!=null) { //从xml文件中定义的filter会保存在这个数组中
for (int i=0;i<_filters.length;i++) { //遍历所有定义的filter
_filterNameMap.put(_filters[i].getName(),_filters[i]); //这里key是名字,value是filterHolder
_filters[i].setServletHandler(this);
}
}
_servletNameMap.clear(); //清空servlet的与name关联的map
if (_servlets!=null) {
for (int i=0;i<_servlets.length;i++) { //遍历所有定义的servlet
_servletNameMap.put(_servlets[i].getName(),_servlets[i]);
_servlets[i].setServletHandler(this);
}
}
}
这段代码应该算是很简单的吧,这里首先遍历filter数组,里面保存了在启动的时候从默认以及用户定义的xml文件中定义的所有的filter,当然它被包装成了filterHolder,然后将他们放到map里面,key是这个filter的名字,value就是当前这个filterHolder了。。。下面对servlet的处理都是一样的。。。
那么接下来来看看updateMappings方法吧:
//这里主要是是设置pathmap
protected synchronized void updateMappings() {
if (_filterMappings==null) {
_filterPathMappings=null;
_filterNameMappings=null;
} else {
_filterPathMappings=new ArrayList();
_filterNameMappings=new MultiMap();
//遍历xml中定义的所有的fitler的map信息
for (int i=0;i<_filterMappings.length;i++) {
//获取相应的filterholder
FilterHolder filter_holder = (FilterHolder)_filterNameMap.get(_filterMappings[i].getFilterName());
if (filter_holder==null)
throw new IllegalStateException("No filter named "+_filterMappings[i].getFilterName());
_filterMappings[i].setFilterHolder(filter_holder);
if (_filterMappings[i].getPathSpecs()!=null)
_filterPathMappings.add(_filterMappings[i]); //如果需要path,那么将其放到pathMap里面去
//有的filter指定了servlet,那么需要将servlet的名字与当前的filterHolder对应
if (_filterMappings[i].getServletNames()!=null) {
String[] names=_filterMappings[i].getServletNames();
for (int j=0;j<names.length;j++)
{
if (names[j]!=null)
_filterNameMappings.add(names[j], _filterMappings[i]); //这里key是servlet的名字
}
}
}
}
//将path与servletholder对应起来
if (_servletMappings==null || _servletNameMap==null) {
_servletPathMap=null;
} else {
PathMap pm = new PathMap(); //创建pathmap
//遍历所有从xml文件中读出的servlet的map信息,保存的是用户定义的servlet与其map的信息,一个servlet可能会map到多个path
for (int i=0;i<_servletMappings.length;i++) {
//获取servlethodler
ServletHolder servlet_holder = (ServletHolder)_servletNameMap.get(_servletMappings[i].getServletName());
if (servlet_holder==null) {
throw new IllegalStateException("No such servlet: "+_servletMappings[i].getServletName());
} else if (_servletMappings[i].getPathSpecs()!=null) {
String[] pathSpecs = _servletMappings[i].getPathSpecs(); //获取这个servlet指定的要处理的path
for (int j=0;j<pathSpecs.length;j++)
if (pathSpecs[j]!=null)
pm.put(pathSpecs[j],servlet_holder); //将path与servletholder放到pahtmap里面去
}
}
_servletPathMap=pm;
}
if (Log.isDebugEnabled()) {
Log.debug("filterNameMap="+_filterNameMap);
Log.debug("pathFilters="+_filterPathMappings);
Log.debug("servletFilterMap="+_filterNameMappings);
Log.debug("servletPathMap="+_servletPathMap);
Log.debug("servletNameMap="+_servletNameMap);
}
try {
if (isStarted()) {
initialize();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
代码也还算是比较的简单吧,这里遍历的对象是我们在xml配置文件中定义的一些mapping项,然后进行相应的处理。。
例如,对于filter,我们可以定义它处理的path,也可以为其指定特定的servlet,因此在filter这里需要维护filterPathMapping与filterNameMapping两个对应关系。。。
对于servlet的处理就稍微要简单些了,主需要处理与path相关的对应就可以了,将其放到pathMap里面。。。
//这里的target就是处理过的了,去掉了前面的contextPath,然后删去了最后的参数
//这里会用target来匹配住合适的servlet来处理
public void handle(String target, HttpServletRequest request,HttpServletResponse response, int type)
throws IOException, ServletException {
if (!isStarted())
return;
// Get the base requests
//其实这里获取base_request一般情况下就是当前的request
final Request base_request=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();
//获取上次这个request的处理的一些信息,为了待会处理失败之后可以恢复现场
final String old_servlet_name=base_request.getServletName(); //上一次request处理的servlet的名字(要知道request对象也是会复用的)
final String old_servlet_path=base_request.getServletPath();
final String old_path_info=base_request.getPathInfo();
final Map old_role_map=base_request.getRoleMap();
try {
ServletHolder servlet_holder=null; //待会用这个指向找出来的servletHolder
FilterChain chain=null;
// find the servlet
if (target.startsWith("/")) {
PathMap.Entry entry=getHolderEntry(target); //通过targer的匹配,找出合适的servletholder
if (entry!=null) { //如果可以找到合适的servlet
servlet_holder = (ServletHolder)entry.getValue(); //获取相应的servletHodler
base_request.setServletName(servlet_holder.getName()); //设置servlet的一些基本信息
base_request.setRoleMap(servlet_holder.getRoleMap());
if(Log.isDebugEnabled())Log.debug("servlet="+servlet_holder);
String servlet_path_spec=(String)entry.getKey(); //获取匹配到的servlet的path信息
String servlet_path=entry.getMapped()!=null?entry.getMapped():PathMap.pathMatch(servlet_path_spec,target);
String path_info=PathMap.pathInfo(servlet_path_spec,target);
if (type==INCLUDE) {
base_request.setAttribute(Dispatcher.__INCLUDE_SERVLET_PATH,servlet_path);
base_request.setAttribute(Dispatcher.__INCLUDE_PATH_INFO, path_info);
} else {
base_request.setServletPath(servlet_path);
base_request.setPathInfo(path_info);
}
if (servlet_holder!=null && _filterMappings!=null && _filterMappings.length>0) {
chain=getFilterChain(type, target, servlet_holder); //组装一个filter链,待会处理会先调用filter,然后在调用servlet
}
}
} else { //如果targer不是以“/”开始的,那么表示不是以path来匹配的,所以要用名字来找servlet
servlet_holder=(ServletHolder)_servletNameMap.get(target); //通过名字来寻找servletholder
if (servlet_holder!=null && _filterMappings!=null && _filterMappings.length>0)
{
base_request.setServletName(servlet_holder.getName());
chain=getFilterChain(type, null,servlet_holder); //构成链
}
}
if (Log.isDebugEnabled()) {
Log.debug("chain="+chain);
Log.debug("servlet holder="+servlet_holder);
}
// Do the filter/handling thang
//先进行filter的操作,然后处理http请求
if (servlet_holder!=null)
{
base_request.setHandled(true); //这里设置一个标志位,表示这个http请求已经处理过了
if (chain!=null) { //如果有filter链,那么还需要先从filter来开始执行
chain.doFilter(request, response);
} else { //如果没有的话,那么直接调用servletholder的handle方法来处理就好了,这期其实也就是调用实际的servlet的service方法
servlet_holder.handle(request,response);
}
} else {
notFound(request, response); //这里表示找不到处理
}
}
代码应该很容易就能够看明白吧,这里首先需要根据target来获取相应的servletHolder,而且然后还要获取需要执行的filter,将他们构成链条,在filter执行完了以后再经由servlet来处理这次http请求。。。。
这里通过target来获取相应的servletholder调用的是getHolderEntry方法,其实这个方法的定义也非常的简单,无非就是直接从前面提到的pathMap里面获得相应的servletHolder就好了。。。
好了,这篇文章之后,应该对jetty的整个http的处理流程就已经很清楚了。。。。
可能以后关于jetty的文章都是这种比较细节的了吧,毕竟整体的东西都差不多了。。。