这几天有点杂事,没有怎么看代码了,今天来把最下层的Container对象看了吧,这里之所以说它是最下层的container对象,是因为它不能在调用addChild方法来添加其他的子container对象了。。。
StandarWrapper,嗯,其实可以将其理解为对servlet对象的包装。。。先来看看简单的继承结构吧:
这里的继承体系还算是比较简单吧,首先是继承了ContainerBase,让StandarWrapper有了基本的对Container的管理能力,其实是先了ServletConfig接口,这个接口应该比较熟悉吧,在servlet的初始化的时候,传进去的就是这个参数,另外就是还有实现了Wrapper接口和NotificationEmitter。。。
从前面可以知道,Wrapper对象是在ContextConfig对象中解析web应用程序的配置的时候创建的,它会读取配置文件里面申明的class属性,name,以及一些参数等。。。
这里先来看看Wrapper接口的定义吧:
//wrapper接口的定义,这里可以理解为对servlet的包装 public interface Wrapper extends Container { //一些事件的定义,主要是添加和移除map的信息 public static final String ADD_MAPPING_EVENT = "addMapping"; public static final String REMOVE_MAPPING_EVENT = "removeMapping"; // 返回这个servlet还需要多长时间可以用 public long getAvailable(); // public void setAvailable(long available); //是否要在加载的时候启动,如果是负的话,那么表示在第一次调用的时候启动 public int getLoadOnStartup(); public void setLoadOnStartup(int value); public String getRunAs(); public void setRunAs(String runAs); //servlet的class public String getServletClass(); // 设置servlet的class public void setServletClass(String servletClass); //servlet支持的所有方法 public String[] getServletMethods() throws ServletException; //现在是否不能用 public boolean isUnavailable(); //返回servlet对象 public Servlet getServlet(); //设置关联的servlet对象 public void setServlet(Servlet servlet); //添加servlet的初始化参数 public void addInitParameter(String name, String value); //添加监听 public void addInstanceListener(InstanceListener listener); //为当前servlet添加map信息 public void addMapping(String mapping); public void addSecurityReference(String name, String link); //这里表示分配一个servlet对象,这里会区分当前servlet的环境,如果不是单线程模式的吧,那么所有的都返回同一个对象 public Servlet allocate() throws ServletException; //表示返回一个servlet到pool里面,只有在servlet配置为单线程模式的时候才有用 public void deallocate(Servlet servlet) throws ServletException; //获取一个初始化的参数的值 public String findInitParameter(String name); //返回所有的初始化参数的名字 public String[] findInitParameters(); //返回这个servlet所有的map信息 public String[] findMappings(); public String findSecurityReference(String name); public String[] findSecurityReferences(); //增加错误计数 public void incrementErrorCount(); //加载并初始化servlet对象 public void load() throws ServletException; //移除一个初始化的参数 public void removeInitParameter(String name); //移除listener public void removeInstanceListener(InstanceListener listener); //移除一个mapping信息 public void removeMapping(String mapping); public void removeSecurityReference(String name); public void unavailable(UnavailableException unavailable); //这里表示卸载所有的servlet实例 public void unload() throws ServletException; public MultipartConfigElement getMultipartConfigElement(); public void setMultipartConfigElement( MultipartConfigElement multipartConfig); //该servlet是否支持异步 public boolean isAsyncSupported(); public void setAsyncSupported(boolean asyncSupport); //当前关联的servlet是否可用 public boolean isEnabled(); public void setEnabled(boolean enabled); public void setServletSecurityAnnotationScanRequired(boolean b); public void servletSecurityAnnotationScan() throws ServletException; public boolean isOverridable(); public void setOverridable(boolean overridable); }
嗯,方法的定义虽然还比较的多,但其实都还算是比较简答的,首先是两个事件的定义,分别是添加和移除map的信息,然后就还有一些属性的设置和获取的方法,最后还有比较重要的就是load方法,用于加载servlet对象。。
这里先来看看构造方法和一些重要的属性申明吧:
protected static final String[] DEFAULT_SERVLET_METHODS = new String[] { "GET", "HEAD", "POST" }; public StandardWrapper() { super(); swValve=new StandardWrapperValve(); //创建pipeline上的basic的valve对象 pipeline.setBasic(swValve); broadcaster = new NotificationBroadcasterSupport(); } protected long available = 0L; //还需要多少事件当前servlet可以用,如果是0的话,那么表示servlet现在就可以用了 protected final NotificationBroadcasterSupport broadcaster; protected final AtomicInteger countAllocated = new AtomicInteger(0); //已经分配了servlet对象的数目,单线程模式下 protected final StandardWrapperFacade facade = new StandardWrapperFacade(this); //servletConfig对象,用于维护servlet的初始化参数什么的,其实是对standerWrapper进行了包装 protected volatile Servlet instance = null; //共享模式下的对象 protected volatile boolean instanceInitialized = false; //用于标记servlet对象是否初始化 protected final InstanceSupport instanceSupport = new InstanceSupport(this); //用于处理一些实例的事件 protected int loadOnStartup = -1; //是否在加载的时候启动servlet,默认不是 protected final ArrayList<String> mappings = new ArrayList<>(); //这个servlet的所有mapping信息 protected HashMap<String, String> parameters = new HashMap<>(); //初始化参数 protected HashMap<String, String> references = new HashMap<>(); protected String runAs = null; protected long sequenceNumber = 0; //通知的序列号 protected String servletClass = null; //servlet对象的class protected volatile boolean singleThreadModel = false; //是否是单线程模型,如果是的话,每一个线程将会独占一个servlet对象 protected boolean unloading = false; //当前是否在卸载servlet对象 protected int maxInstances = 20; //最大的servlet对象数量 protected int nInstances = 0; //当前已经实例化的servlet对象数量(在单线程模式下用) protected Stack<Servlet> instancePool = null; //在单线程模式下,将会维护一个servlet的对象池 protected long unloadDelay = 2000; protected boolean isJspServlet; //是不是jsp的servlet protected ObjectName jspMonitorON; protected boolean swallowOutput = false; //是否要重定向servlet的system.out到log // To support jmx attributes protected StandardWrapperValve swValve; //pipeline上面的基本valve对象 protected long loadTime=0; protected int classLoadTime=0; protected MultipartConfigElement multipartConfigElement = null; //multipart的配置 protected boolean asyncSupported = false; //是否支持异步 protected boolean enabled = true; //是否可用 protected volatile boolean servletSecurityAnnotationScanRequired = false; //安全注释扫描 private boolean overridable = false;
这里构造方法其实主要是在pipeline上面添加一个basic类型的valve对象。。然后对于下面属性的申明,应该注释也说的比较清楚吧。。。
这里再来看看比较重要的load方法吧,看看是如何加载servlet对象的。。。
//加载并初始化servlet,还要在jmx上面注册 public synchronized void load() throws ServletException { instance = loadServlet(); if (!instanceInitialized) { initServlet(instance); } // 如果是jsp的servlet的话,那么需要进行jmx上面的注册 if (isJspServlet) { StringBuilder oname = new StringBuilder(getDomain()); oname.append(":type=JspMonitor"); oname.append(getWebModuleKeyProperties()); oname.append(",name="); oname.append(getName()); oname.append(getJ2EEKeyProperties()); try { jspMonitorON = new ObjectName(oname.toString()); Registry.getRegistry(null, null) .registerComponent(instance, jspMonitorON, null); } catch( Exception ex ) { log.info("Error registering JSP monitoring with jmx " + instance); } } }
这里好像没啥意思吧,首先是调用loadServlet方法来加载servlet对象,用instance来引用。。然后调用initServlet方法来初始化servlet.好了,那就先来看看loadServlet方法吧:
// 加载servlet对象 public synchronized Servlet loadServlet() throws ServletException { // Nothing to do if we already have an instance or an instance pool if (!singleThreadModel && (instance != null)) //如果不是单线程模式,而且有instanc了,那么直接返回吧 return instance; PrintStream out = System.out; if (swallowOutput) { //是否将servle的system.out输出定向到log SystemLogHandler.startCapture(); } Servlet servlet; try { long t1=System.currentTimeMillis(); //获取当前时间 // Complain if no servlet class has been specified if (servletClass == null) { //这里都没有class,那么返回错误吧 unavailable(null); throw new ServletException (sm.getString("standardWrapper.notClass", getName())); } //其实最终还是调用webappclassLoader来载入class,然后再创建对象的 InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager(); //获取所属context的instanceManager对象 try { servlet = (Servlet) instanceManager.newInstance(servletClass); //调用instanceManager来加载servlet的class,并创建 } catch (ClassCastException e) { unavailable(null); // Restore the context ClassLoader throw new ServletException (sm.getString("standardWrapper.notServlet", servletClass), e); } catch (Throwable e) { e = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(e); unavailable(null); // Added extra log statement for Bugzilla 36630: // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630 if(log.isDebugEnabled()) { log.debug(sm.getString("standardWrapper.instantiate", servletClass), e); } // Restore the context ClassLoader throw new ServletException (sm.getString("standardWrapper.instantiate", servletClass), e); } if (multipartConfigElement == null) { MultipartConfig annotation = servlet.getClass().getAnnotation(MultipartConfig.class); //获取multipart的注释申明 if (annotation != null) { multipartConfigElement = new MultipartConfigElement(annotation); } } processServletSecurityAnnotation(servlet.getClass()); //处理安全注释 // Special handling for ContainerServlet instances if ((servlet instanceof ContainerServlet) && (isContainerProvidedServlet(servletClass) || ((Context) getParent()).getPrivileged() )) { ((ContainerServlet) servlet).setWrapper(this); //这个一般很少 } classLoadTime=(int) (System.currentTimeMillis() -t1); //加载对象所用的时间 if (servlet instanceof SingleThreadModel) { //如果是单线程模式,那么这里可能还要初始化池 if (instancePool == null) { instancePool = new Stack<>(); } singleThreadModel = true; } initServlet(servlet); // 初始化servlet fireContainerEvent("load", this); loadTime=System.currentTimeMillis() -t1; } finally { if (swallowOutput) { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { if (getServletContext() != null) { getServletContext().log(log); } else { out.println(log); } } } } return servlet; }
代码应该很简单吧,无非是调用context的instanceManager对象来创建servlet对象,当然这里还要区分servlet是否是单线程模式。。。其他的代码上面注释应该也还算比较清楚吧。。都比较的简单。。。
那么再来看看如何初始化servlet吧:
//初始化serlvet private synchronized void initServlet(Servlet servlet) throws ServletException { if (instanceInitialized && !singleThreadModel) return; // Call the initialization method of this servlet try { instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT, servlet); if( Globals.IS_SECURITY_ENABLED) { boolean success = false; try { Object[] args = new Object[] { facade }; SecurityUtil.doAsPrivilege("init", servlet, classType, args); success = true; } finally { if (!success) { // destroy() will not be called, thus clear the reference now SecurityUtil.remove(servlet); } } } else { servlet.init(facade); //初始化servlet } instanceInitialized = true; instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet); } catch (UnavailableException f) { instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); unavailable(f); throw f; } catch (ServletException f) { instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); // If the servlet wanted to be unavailable it would have // said so, so do not call unavailable(null). throw f; } catch (Throwable f) { ExceptionUtils.handleThrowable(f); getServletContext().log("StandardWrapper.Throwable", f ); instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); // If the servlet wanted to be unavailable it would have // said so, so do not call unavailable(null). throw new ServletException (sm.getString("standardWrapper.initException", getName()), f); } }
这里其实init方法传入的是facade对象,它是一个门面模式吧,其实是对当前standarWrapper对象的一个包装。。。
好了,其实到这里standardWrapper的主要的东西都差不多了。。这里再来看看StandardWrapperValve类型吧,其实最终处理请求还是调用它的invoke方法来处理的。。。
先来看看一些基本的属性的定义:
private volatile long processingTime; //请求的处理事件 private volatile long maxTime; //处理这里http请求的最大耗费的时间 private volatile long minTime = Long.MAX_VALUE; //处理这次http请求最短耗费的时间 private final AtomicInteger requestCount = new AtomicInteger(0); //用于请求的计数 private final AtomicInteger errorCount = new AtomicInteger(0); //用于记录错误数量
嗯,其实从名字就基本上就能知道这些属性是干嘛的。。。
接下来来看看最重要的invoke方法吧:
// 在context的pipeline里面会调用wrapper对象的pipeline来处理请求 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.incrementAndGet(); //请求计数加1 StandardWrapper wrapper = (StandardWrapper) getContainer(); //获取所属的container对象,其实也就是wrapper Servlet servlet = null; Context context = (Context) wrapper.getParent(); //获取context // Check for the application being marked unavailable if (!context.getState().isAvailable()) { //如果context不可用,那么表示当前服务不可用,返回错误就好了 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString("standardContext.isUnavailable")); unavailable = true; } // Check for the servlet being marked unavailable if (!unavailable && wrapper.isUnavailable()) { //当前servlet暂时不可用 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) { //当前的servlet可以用 servlet = wrapper.allocate(); //获取servlet对象 } } catch (UnavailableException e) { container.getLogger().error( sm.getString("standardWrapper.allocateException", wrapper.getName()), e); 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())); } } catch (ServletException e) { container.getLogger().error(sm.getString("standardWrapper.allocateException", wrapper.getName()), StandardWrapper.getRootCause(e)); throwable = e; exception(request, response, e); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString("standardWrapper.allocateException", wrapper.getName()), e); throwable = e; exception(request, response, e); servlet = null; } // Identify if the request is Comet related now that the servlet has been allocated boolean comet = false; if (servlet instanceof CometProcessor && request.getAttribute( //看当前servlet是否支持comet Globals.COMET_SUPPORTED_ATTR) == Boolean.TRUE) { comet = true; request.setComet(true); } MessageBytes requestPathMB = request.getRequestPathMB(); //获取当前请求的path /examples 啥的 DispatcherType dispatcherType = DispatcherType.REQUEST; //设置当前请求的类型 if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC; request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType); //设置派遣类型,是否是异步的啥的,或者就是普通的request request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, requestPathMB); //设置path属性 // Create the filter chain for this request ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance(); //创建filter ApplicationFilterChain filterChain = //创建filterChain,先调用filter来处理请求,在调用servlet的servie方法 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 { if ((servlet != null) && (filterChain != null)) { // Swallow output if needed if (context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); if (request.isAsyncDispatching()) { // 如果是异步的执行 ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch(); } else if (comet) { //如果是comet的话,执行这里 filterChain.doFilterEvent(request.getEvent()); request.setComet(true); } else { filterChain.doFilter(request.getRequest(), //一般情况下是坐这里,在filter调用完了之后,会调用servlet的service方法 response.getResponse()); } } finally { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { context.getLogger().info(log); } } } else { if (request.isAsyncDispatching()) { ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch(); } else if (comet) { request.setComet(true); filterChain.doFilterEvent(request.getEvent()); } else { filterChain.doFilter (request.getRequest(), response.getResponse()); } } } } catch (ClientAbortException e) { throwable = e; exception(request, response, e); } catch (IOException e) { container.getLogger().error(sm.getString( "standardWrapper.serviceException", wrapper.getName(), context.getName()), e); throwable = e; exception(request, response, e); } catch (UnavailableException e) { container.getLogger().error(sm.getString( "standardWrapper.serviceException", wrapper.getName(), context.getName()), e); // throwable = e; // exception(request, response, e); wrapper.unavailable(e); 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())); } // Do not save exception in ‘throwable‘, because we // do not want to do exception(request, response, e) processing } catch (ServletException e) { Throwable rootCause = StandardWrapper.getRootCause(e); if (!(rootCause instanceof ClientAbortException)) { container.getLogger().error(sm.getString( "standardWrapper.serviceExceptionRoot", wrapper.getName(), context.getName(), e.getMessage()), rootCause); } throwable = e; exception(request, response, e); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString( "standardWrapper.serviceException", wrapper.getName(), context.getName()), e); throwable = e; exception(request, response, e); } // Release the filter chain (if any) for this request if (filterChain != null) { if (request.isComet()) { //如果是comet类型的话, // If this is a Comet request, then the same chain will be used for the // processing of all subsequent events. filterChain.reuse(); //那么可以重用这个filter链 } else { filterChain.release(); //如果不是comet的话,那么可以释放了 } } // Deallocate the allocated servlet instance try { if (servlet != null) { wrapper.deallocate(servlet); // 相当于释放servlet,只有在配置servlet为单线程的时候才有用,将会返还到pool } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString("standardWrapper.deallocateException", wrapper.getName()), e); if (throwable == null) { throwable = e; exception(request, response, 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) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString("standardWrapper.unloadException", wrapper.getName()), e); if (throwable == null) { throwable = e; exception(request, response, e); } } long t2=System.currentTimeMillis(); long time=t2-t1; processingTime += time; //处理耗费时间 if( time > maxTime) maxTime=time; //设置最大处理时间 if( time < minTime) minTime=time; //设置最小处理时间 }
代码够长吧,不过注释应该也交代清楚了。。首先调用allocate方法来获取一个servlet对象,然后在最终调用servlet对象的service方法来处理之前还需要先ApplicationFilterChain对象来包装filter对象,然后再调用doFilter方法,先执行filter,然后在里面才回调用servlet来处理。。
这里发现,其实每次都要构造新的ApplicationFilterChain对象,并没有做缓存。。是不是不太好呢。。?起码在jetty中这部分是做了缓存的。。。
好了,到这里standarwrapper就差不多了吧。。写的比较粗糙。。