从零开始手写Tomcat的教程11节----StandardWrapper
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始手写Tomcat的教程11节----StandardWrapper相关的知识,希望对你有一定的参考价值。
从零开始手写Tomcat的教程11节----StandardWrapper
本节内容与之前这节有着很大的关系,建议各位先回顾一下:
方法调用序列
SingleThreadModel类
StandardWrapper类
这里实现的是针对某个方法的同步执行,思路有两个: 同步锁,对象池实现对象复用
分配servlet实例
public Servlet allocate() throws ServletException;
// If not SingleThreadedModel, return the same instance every time
if (!singleThreadModel)
...
synchronized (instancePool)
//return an instance of the servlet from the pool
/**
* The (single) initialized instance of this servlet.
*/
private Servlet instance = null;
// If not SingleThreadedModel, return the same instance every time
if (!singleThreadModel)
// Load and initialize our instance if necessary
//为了实现单例模式,采用的是双重锁校验
if (instance == null)
synchronized (this)
if (instance == null)
try
instance = loadServlet();
catch (ServletException e)
throw e;
catch (Throwable e)
throw new ServletException
(sm.getString("standardWrapper.allocate"), e);
if (!singleThreadModel)
if (debug >= 2)
log(" Returning non-STM instance");
countAllocated++;
return (instance);
/**
* Stack containing the STM instances.
*/
private Stack instancePool = null;
/**
* Maximum number of STM instances.
*/
private int maxInstances = 20;
/**
* Number of instances currently loaded for a STM servlet.
*/
private int nInstances = 0;
记录已经创建的存活的servlet对象实例个数,包括STM和non-STM的servlet类实例
/**
* The count of allocations that are currently active (even if they
* are for the same instance, as will be true on a non-STM servlet).
*/
private int countAllocated = 0;
下面是allocate方法的第二部分:
synchronized (instancePool)
while (countAllocated >= nInstances)
// Allocate a new instance if possible, or else wait
if (nInstances < maxInstances)
try
instancePool.push(loadServlet());
nInstances++;
catch (ServletException e)
throw e;
catch (Throwable e)
throw new ServletException
(sm.getString("standardWrapper.allocate"), e);
else
try
instancePool.wait();
catch (InterruptedException e)
;
if (debug >= 2)
log(" Returning allocated STM instance");
countAllocated++;
return (Servlet) instancePool.pop();
allocate方法完整源码:
/**
* Allocate an initialized instance of this Servlet that is ready to have
* its <code>service()</code> method called. If the servlet class does
* not implement <code>SingleThreadModel</code>, the (only) initialized
* instance may be returned immediately. If the servlet class implements
* <code>SingleThreadModel</code>, the Wrapper implementation must ensure
* that this instance is not allocated again until it is deallocated by a
* call to <code>deallocate()</code>.
*
* @exception ServletException if the servlet init() method threw
* an exception
* @exception ServletException if a loading error occurs
*/
public Servlet allocate() throws ServletException
if (debug >= 1)
log("Allocating an instance");
// If we are currently unloading this servlet, throw an exception
if (unloading)
throw new ServletException
(sm.getString("standardWrapper.unloading", getName()));
// If not SingleThreadedModel, return the same instance every time
if (!singleThreadModel)
// Load and initialize our instance if necessary
if (instance == null)
synchronized (this)
if (instance == null)
try
instance = loadServlet();
catch (ServletException e)
throw e;
catch (Throwable e)
throw new ServletException
(sm.getString("standardWrapper.allocate"), e);
if (!singleThreadModel)
if (debug >= 2)
log(" Returning non-STM instance");
countAllocated++;
return (instance);
synchronized (instancePool)
while (countAllocated >= nInstances)
// Allocate a new instance if possible, or else wait
if (nInstances < maxInstances)
try
instancePool.push(loadServlet());
nInstances++;
catch (ServletException e)
throw e;
catch (Throwable e)
throw new ServletException
(sm.getString("standardWrapper.allocate"), e);
else
try
instancePool.wait();
catch (InterruptedException e)
;
if (debug >= 2)
log(" Returning allocated STM instance");
countAllocated++;
return (Servlet) instancePool.pop();
载入servlet实例
public synchronized void load() throws ServletException
instance = loadServlet();
/**
* Load and initialize an instance of this servlet, if there is not already
* at least one initialized instance. This can be used, for example, to
* load servlets that are marked in the deployment descriptor to be loaded
* at server startup time.
*/
public synchronized Servlet loadServlet() throws ServletException
// Nothing to do if we already have an instance or an instance pool
if (!singleThreadModel && (instance != null))
return instance;
PrintStream out = System.out;
SystemLogHandler.startCapture();
Servlet servlet = null;
try
// If this "servlet" is really a JSP file, get the right class.
String actualClass = servletClass;
if ((actualClass == null) && (jspFile != null))
Wrapper jspWrapper = (Wrapper)
((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);
if (jspWrapper != null)
actualClass = jspWrapper.getServletClass();
// Complain if no servlet class has been specified
if (actualClass == null)
unavailable(null);
throw new ServletException
(sm.getString("standardWrapper.notClass", getName()));
// Acquire an instance of the class loader to be used
Loader loader = getLoader();
if (loader == null)
unavailable(null);
throw new ServletException
(sm.getString("standardWrapper.missingLoader", getName()));
ClassLoader classLoader = loader.getClassLoader();
// Special case class loader for a container provided servlet
if (isContainerProvidedServlet(actualClass))
classLoader = this.getClass().getClassLoader();
log(sm.getString
("standardWrapper.containerServlet", getName()));
// Load the specified servlet class from the appropriate class loader
Class classClass = null;
try
if (classLoader != null)
classClass = classLoader.loadClass(actualClass);
else
classClass = Class.forName(actualClass);
catch (ClassNotFoundException e)
unavailable(null);
throw new ServletException
(sm.getString("standardWrapper.missingClass", actualClass),
e);
if (classClass == null)
unavailable(null);
throw new ServletException
(sm.getString("standardWrapper.missingClass", actualClass));
// Instantiate and initialize an instance of the servlet class itself
try
servlet = (Servlet) classClass.newInstance();
catch (ClassCastException e)
unavailable(null);
// Restore the context ClassLoader
throw new ServletException
(sm.getString("standardWrapper.notServlet", actualClass), e);
catch (Throwable e)
unavailable(null);
// Restore the context ClassLoader
throw new ServletException
(sm.getString("standardWrapper.instantiate", actualClass), e);
// Check if loading the servlet in this web application should be
// allowed
if (!isServletAllowed(servlet))
throw new SecurityException
(sm.getString("standardWrapper.privilegedServlet",
actualClass));
// Special handling for ContainerServlet instances
if ((servlet instanceof ContainerServlet) &&
isContainerProvidedServlet(actualClass))
((ContainerServlet) servlet).setWrapper(this);
// Call the initialization method of this servlet
try
instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,
servlet);
servlet.init(facade);
// Invoke jspInit on JSP pages
if ((loadOnStartup > 0) && (jspFile != null))
// Invoking jspInit
HttpRequestBase req = new HttpRequestBase();
HttpResponseBase res = new HttpResponseBase();
req.setServletPath(jspFile);
req.setQueryString("jsp_precompile=true");
servlet.service(req, res);
instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
servlet);
// Register our newly initialized instance
singleThreadModel = servlet instanceof SingleThreadModel;
if (singleThreadModel)
if (instancePool == null)
instancePool = new Stack();
fireContainerEvent("load", this);
finally
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0)
if (getServletContext() != null)
getServletContext().log(log);
else
out.println(log);
return servlet;
loadServlet方法完整源码:
/**
* Load and initialize an instance of this servlet, if there is not already
* at least one initialized instance. This can be used, for example, to
* load servlets that are marked in the deployment descriptor to be loaded
* at server startup time.
*/
public synchronized Servlet loadServlet() throws ServletException
// Nothing to do if we already have an instance or an instance pool
if (!singleThreadModel && (instance != null))
return instance;
PrintStream out = System.out;
SystemLogHandler.startCapture();
Servlet servlet = null;
try
// If this "servlet" is really a JSP file, get the right class.
// HOLD YOUR NOSE - this is a kludge that avoids having to do special
// case Catalina-specific code in Jasper - it also requires that the
// servlet path be replaced by the <jsp-file> element content in
// order to be completely effective
String actualClass = servletClass;
if ((actualClass == null) && (jspFile != null))
Wrapper jspWrapper = (Wrapper)
((Context) getParent()).findChild(org.apache.catalina.core.Constants.JSP_SERVLET_NAME);
if (jspWrapper != null)
actualClass = jspWrapper.getServletClass();
// Complain if no servlet class has been specified
if (actualClass == null)
unavailable(null);
throw new ServletException
(sm.getString("standardWrapper.notClass", getName()));
// Acquire an instance of the class loader to be used
Loader loader = getLoader();
if (loader == null)
unavailable(null);
throw new ServletException
(sm.getString(从零开始手写Tomcat的教程6节----生命周期