从零开始手写Tomcat的教程12节----StandardContext
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始手写Tomcat的教程12节----StandardContext相关的知识,希望对你有一定的参考价值。
从零开始手写Tomcat的教程12节----StandardContext
StandardContext的配置
StandardContext类的构造函数
/**
* Create a new StandardContext component with the default basic Valve.
*/
public StandardContext()
super();
pipeline.setBasic(new org.apache.catalina.core.StandardContextValve());
namingResources.setContainer(this);
启动StandardContext类的实例
/**
* Start this Context component.
*
* @exception LifecycleException if a startup error occurs
*/
public synchronized void start() throws LifecycleException
//防止重复启动
if (started)
throw new LifecycleException
(sm.getString("containerBase.alreadyStarted", logName()));
if (debug >= 1)
log("Starting");
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
if (debug >= 1)
log("Processing start(), current available=" + getAvailable());
setAvailable(false);
setConfigured(false);
boolean ok = true;
//设置资源
// Add missing components as necessary
if (getResources() == null) // (1) Required by Loader
if (debug >= 1)
log("Configuring default Resources");
try
//当前应用程序是一个war包还是一个目录---联想tomcat会自动解压webapp下面的war包
if ((docBase != null) && (docBase.endsWith(".war")))
setResources(new WARDirContext());
else
setResources(new FileDirContext());
catch (IllegalArgumentException e)
log("Error initializing resources: " + e.getMessage());
ok = false;
if (ok && (resources instanceof ProxyDirContext))
DirContext dirContext =
((ProxyDirContext) resources).getDirContext();
if ((dirContext != null)
&& (dirContext instanceof BaseDirContext))
((BaseDirContext) dirContext).setDocBase(getBasePath());
((BaseDirContext) dirContext).allocate();
//设置加载器
if (getLoader() == null) // (2) Required by Manager
if (getPrivileged())
if (debug >= 1)
log("Configuring privileged default Loader");
//该方法会设置载入器,然后发出firePropertyChange事件
setLoader(new WebappLoader(this.getClass().getClassLoader()));
else
if (debug >= 1)
log("Configuring non-privileged default Loader");
setLoader(new WebappLoader(getParentClassLoader()));
//设置session管理器
if (getManager() == null) // (3) After prerequisites
if (debug >= 1)
log("Configuring default Manager");
//该方法会设置session管理器,然后发出firePropertyChange事件
setManager(new StandardManager());
//初始化字符集映射器
// Initialize character set mapper
getCharsetMapper();
// Post work directory
postWorkDirectory();
// Reading the "catalina.useNaming" environment variable
String useNamingProperty = System.getProperty("catalina.useNaming");
if ((useNamingProperty != null)
&& (useNamingProperty.equals("false")))
useNaming = false;
if (ok && isUseNaming())
if (namingContextListener == null)
namingContextListener = new NamingContextListener();
namingContextListener.setDebug(getDebug());
namingContextListener.setName(getNamingContextName());
addLifecycleListener(namingContextListener);
// Binding thread
ClassLoader oldCCL = bindThread();
// Standard container startup
if (debug >= 1)
log("Processing standard container startup");
if (ok)
try
//添加默认映射器
addDefaultMapper(this.mapperClass);
started = true;
//下面是启动与该Context容器相关联的组件
// Start our subordinate components, if any
//启动载入器组件
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
if ((logger != null) && (logger instanceof Lifecycle))
((Lifecycle) logger).start();
// Unbinding thread
unbindThread(oldCCL);
// Binding thread
oldCCL = bindThread();
//启动相关组件
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
//启动相关映射器
// Start our Mappers, if any
Mapper mappers[] = findMappers();
for (int i = 0; i < mappers.length; i++)
if (mappers[i] instanceof Lifecycle)
((Lifecycle) mappers[i]).start();
//启动子容器
// Start our child containers, if any
Container children[] = findChildren();
for (int i = 0; i < children.length; i++)
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
// Start the Valves in our pipeline (including the basic),
// if any
//启动管道对象
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
//释放启动事件信号----这里ContextConfig接收并响应该事件
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
//启动session管理器
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
finally
// Unbinding thread
unbindThread(oldCCL);
//是否配置好了
if (!getConfigured())
ok = false;
// We put the resources into the servlet context
if (ok)
getServletContext().setAttribute
(Globals.RESOURCES_ATTR, getResources());
// Binding thread
oldCCL = bindThread();
// Create context attributes that will be required
if (ok)
if (debug >= 1)
log("Posting standard context attributes");
postWelcomeFiles();
// Configure and call application event listeners and filters
if (ok)
if (!listenerStart())
ok = false;
if (ok)
if (!filterStart())
ok = false;
// Load and initialize all "load on startup" servlets
if (ok)
//调用下面的方法来载入哪些需要在启动就载入的子容器,例如Wrapper实例
loadOnStartup(findChildren());
// Unbinding thread
unbindThread(oldCCL);
// Set available status depending upon startup success
if (ok)
if (debug >= 1)
log("Starting completed");
setAvailable(true);
else
log(sm.getString("standardContext.startFailed"));
try
stop();
catch (Throwable t)
log(sm.getString("standardContext.startCleanup"), t);
setAvailable(false);
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
上面在13处有问题,应该是调用loadOnStartup方法
/**
* Load and initialize all servlets marked "load on startup" in the
* web application deployment descriptor.
*
* @param children Array of wrappers for all currently defined
* servlets (including those not declared load on startup)
*/
public void loadOnStartup(Container children[])
// Collect "load on startup" servlets that need to be initialized
TreeMap map = new TreeMap();
for (int i = 0; i < children.length; i++)
Wrapper wrapper = (Wrapper) children[i];
int loadOnStartup = wrapper.getLoadOnStartup();
if (loadOnStartup < 0)
continue;
if (loadOnStartup == 0) // Arbitrarily put them last
loadOnStartup = Integer.MAX_VALUE;
Integer key = new Integer(loadOnStartup);
ArrayList list = (ArrayList) map.get(key);
if (list == null)
list = new ArrayList();
map.put(key, list);
list.add(wrapper);
// Load the collected "load on startup" servlets
Iterator keys = map.keySet().iterator();
while (keys.hasNext())
Integer key = (Integer) keys.next();
ArrayList list = (ArrayList) map.get(key);
Iterator wrappers = list.iterator();
while (wrappers.hasNext())
Wrapper wrapper = (Wrapper) wrappers.next();
try
wrapper.load();
catch (ServletException e)
log(sm.getString("standardWrapper.loadException",
getName()), e);
// NOTE: load errors (including a servlet that throws
// UnavailableException from tht init() method) are NOT
// fatal to application startup
从零开始手写Tomcat的教程11节----StandardWrapper
wrapper的load方法会去调用loadServelt方法生成并返回一个与当前wrapper关联的servlet对象
invoke方法
/**
* Process the specified Request, and generate the corresponding Response,
* according to the design of this particular Container.
*
* @param request Request to be processed
* @param response Response to be produced
*
* @exception IOException if an input/output error occurred while
* processing
* @exception ServletException if a ServletException was thrown
* while processing this request
*/
public void invoke(Request request, Response response)
throws IOException, ServletException
// Wait if we are reloading
while (getPaused())
try
Thread.sleep(1000);
catch (InterruptedException e)
;
// Normal request processing
if (swallowOutput)
try
SystemLogHandler.startCapture();
super.invoke(request, response);
finally
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0)
log(log);
else
super.invoke(request, response);
父类ContainerBase的invoke方法:
/**
* Process the specified Request, to produce the corresponding Response,
* by invoking the first Valve in our pipeline (if any), or the basic
* Valve otherwise.
*
* @param request Request to be processed
* @param response Response to be produced
*
* @exception IllegalStateException if neither a pipeline or a basic
* Valve have been configured for this Container
* @exception IOException if an input/output error occurred while
* processing
* @exception ServletException if a ServletException was thrown
* while processing this request
*/
public void invoke(Request request, Response response)
throws IOException, ServletException
pipeline.invoke(request, response);
ContainerBase的成员变量:
/**
* The Pipeline object with which this Container is associated.
*/
protected Pipeline pipeline = new org.apache.catalina.core.StandardPipeline(this);
最终调用的是StandardPipeline的invoke方法:
public void invoke(Request request, Response response)
throws IOException, ServletException
// Invoke the first Valve in this pipeline for this request
(new StandardPipelineValveContext()).invokeNext(request, response);
StandardPipelineValveContext是StandardPipeline的一个内部类,可以访问StandardPipeline的成员属性:
protected class StandardPipelineValveContext
implements ValveContext
protected int stage = 0;
public void invokeNext(Request request, Response response)
throws IOException, ServletException
int subscript = stage;
stage = stage + 1;
// Invoke the requested Valve for the current request thread
if (subscript < valves.length)
valves[subscript].invoke(request, response, this);
else if ((subscript == valves.length) && (basic != null从零开始手写Tomcat的教程6节----生命周期