从零开始手写Tomcat的教程12节----StandardContext
StandardContext的配置
StandardContext类的构造函数
public StandardContext() {
super();
pipeline.setBasic(new org.apache.catalina.core.StandardContextValve());
namingResources.setContainer(this);
}
启动StandardContext类的实例
public synchronized void start() throws LifecycleException {
if (started)
throw new LifecycleException
(sm.getString("containerBase.alreadyStarted", logName()));
if (debug >= 1)
log("Starting");
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
if (debug >= 1)
log("Processing start(), current available=" + getAvailable());
setAvailable(false);
setConfigured(false);
boolean ok = true;
if (getResources() == null) {
if (debug >= 1)
log("Configuring default Resources");
try {
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) {
if (getPrivileged()) {
if (debug >= 1)
log("Configuring privileged default Loader");
setLoader(new WebappLoader(this.getClass().getClassLoader()));
} else {
if (debug >= 1)
log("Configuring non-privileged default Loader");
setLoader(new WebappLoader(getParentClassLoader()));
}
}
if (getManager() == null) {
if (debug >= 1)
log("Configuring default Manager");
setManager(new StandardManager());
}
getCharsetMapper();
postWorkDirectory();
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);
}
}
ClassLoader oldCCL = bindThread();
if (debug >= 1)
log("Processing standard container startup");
if (ok) {
try {
addDefaultMapper(this.mapperClass);
started = true;
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
if ((logger != null) && (logger instanceof Lifecycle))
((Lifecycle) logger).start();
unbindThread(oldCCL);
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();
Mapper mappers[] = findMappers();
for (int i = 0; i < mappers.length; i++) {
if (mappers[i] instanceof Lifecycle)
((Lifecycle) mappers[i]).start();
}
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
}
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
lifecycle.fireLifecycleEvent(START_EVENT, null);
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
} finally {
unbindThread(oldCCL);
}
}
if (!getConfigured())
ok = false;
if (ok)
getServletContext().setAttribute
(Globals.RESOURCES_ATTR, getResources());
oldCCL = bindThread();
if (ok) {
if (debug >= 1)
log("Posting standard context attributes");
postWelcomeFiles();
}
if (ok) {
if (!listenerStart())
ok = false;
}
if (ok) {
if (!filterStart())
ok = false;
}
if (ok)
loadOnStartup(findChildren());
unbindThread(oldCCL);
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);
}
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
上面在13处有问题,应该是调用loadOnStartup方法
public void loadOnStartup(Container children[]) {
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)
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);
}
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);
}
}
}
}
从零开始手写Tomcat的教程11节----StandardWrapper
wrapper的load方法会去调用loadServelt方法生成并返回一个与当前wrapper关联的servlet对象
invoke方法
public void invoke(Request request, Response response)
throws IOException, ServletException {
while (getPaused()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
;
}
}
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方法:
public void invoke(Request request, Response response)
throws IOException, ServletException {
pipeline.invoke(request, response);
}
ContainerBase的成员变量:
protected Pipeline pipeline = new org.apache.catalina.core.StandardPipeline(this);
最终调用的是StandardPipeline的invoke方法:
public void invoke(Request request, Response response)
throws IOException, ServletException {
(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;
if (subscript < valves.length) {
valves[subscript].invoke(request, response, this);
} else if ((subscript == valves.length) && (basic != null)) {
basic.invoke(request, response, this);
} else {
throw new ServletException
(sm.getString("standardPipeline.noValve"));
}
}
}
这是11节末尾画的图,大家可以回顾一下:
StandardContextMapper类
public void addMapper(Mapper mapper) {
synchronized(mappers) {
if (mappers.get(mapper.getProtocol()) != null)
throw new IllegalArgumentException("addMapper: Protocol '" +
mapper.getProtocol() +
"' is not unique");
mapper.setContainer((Container) this);
if (started && (mapper instanceof Lifecycle)) {
try {
((Lifecycle) mapper).start();
} catch (LifecycleException e) {
log("ContainerBase.addMapper: start: ", e);
throw new IllegalStateException
("ContainerBase.addMapper: start: " + e);
}
}
mappers.put(mapper.getProtocol(), mapper);
if (mappers.size() == 1)
this.mapper = mapper;
else
this.mapper = null;
fireContainerEvent(ADD_MAPPER_EVENT, mapper);
}
}
addDefaultMapper(this.mapperClass);
private String mapperClass =
"org.apache.catalina.core.StandardContextMapper";
public void setContainer(Container container) {
if (!(container instanceof StandardContext))
throw new IllegalArgumentException
(sm.getString("httpContextMapper.container"));
context = (StandardContext) container;
}
public Container map(Request request, boolean update);
public Container map(Request request, boolean update) {
Mapper mapper = findMapper(request.getRequest().getProtocol());
if (mapper == null)
return (null);
return (mapper.map(request, update));
}
public Container map(Request request, boolean update) {
int debug = context.getDebug();
if (update && (request.getWrapper() != null))
return (request.getWrapper());
String contextPath =
((HttpServletRequest) request.getRequest()).getContextPath();
String requestURI = ((HttpRequest) request).getDecodedRequestURI();
String relativeURI = requestURI.substring(contextPath.length());
if (debug >= 1)
context.log("Mapping contextPath='" + contextPath +
"' with requestURI='" + requestURI +
"' and relativeURI='" + relativeURI + "'");
Wrapper wrapper = null;
String servletPath = relativeURI;
String pathInfo = null;
String name = null;
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying exact match");
if (!(relativeURI.equals("/")))
name = context.findServletMapping(relativeURI);
if (name != null)
wrapper = (Wrapper) context.findChild(name);
if (wrapper != null) {
servletPath = relativeURI;
pathInfo = null;
}
}
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying prefix match");
servletPath = relativeURI;
while (true) {
name = context.findServletMapping(servletPath + "/*");
if (name != null)
wrapper = (Wrapper) context.findChild(name);
if (wrapper != null) {
pathInfo = relativeURI.substring(servletPath.length());
if (pathInfo.length() == 0)
pathInfo = null;
break;
}
int slash = servletPath.lastIndexOf('/');
if (slash < 0)
break;
servletPath = servletPath.substring(0, slash);
}
}
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying extension match");
int slash = relativeURI.lastIndexOf('/');
if (slash >= 0) {
String last = relativeURI.substring(slash);
int period = last.lastIndexOf('.');
if (period >= 0) {
String pattern = "*" + last.substring(period);
name = context.findServletMapping(pattern);
if (name != null)
wrapper = (Wrapper) context.findChild(name);
if (wrapper != null) {
servletPath = relativeURI;
pathInfo = null;
}
}
}
}
// Rule 4 -- Default Match ----默认匹配
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying default match");
name = context.findServletMapping("/");
if (name != null)
wrapper = (Wrapper) context.findChild(name);
if (wrapper != null) {
servletPath = relativeURI;
pathInfo = null;
}
}
// Update the Request (if requested) and return this Wrapper
if ((debug >= 1) && (wrapper != null))
context.log(" Mapped to servlet '" + wrapper.getName() +
"' with servlet path '" + servletPath +
"' and path info '" + pathInfo +
"' and update=" + update);
//将查询到的wrapper对象设置给当然request对象
if (update) {
request.setWrapper(wrapper);
((HttpRequest) request).setServletPath(servletPath);
((HttpRequest) request).setPathInfo(pathInfo);
}
return (wrapper);
}
对重载的支持
public void setContainer(Container container) {
if ((this.container != null) && (this.container instanceof Context))
((Context) this.container).removePropertyChangeListener(this);
Container oldContainer = this.container;
this.container = container;
support.firePropertyChange("container", oldContainer, this.container);
if ((this.container != null) && (this.container instanceof Context)) {
setReloadable( ((Context) this.container).getReloadable() );
((Context) this.container).addPropertyChangeListener(this);
}
}
public void setReloadable(boolean reloadable) {
boolean oldReloadable = this.reloadable;
this.reloadable = reloadable;
support.firePropertyChange("reloadable",
new Boolean(oldReloadable),
new Boolean(this.reloadable));
if (!started)
return;
if (!oldReloadable && this.reloadable)
threadStart();
else if (oldReloadable && !this.reloadable)
threadStop();
}
backgroundProcess()方法
小结
这里的源码分析针对的是tomcat4版本的
这里我先对StandardContext容器的start方法调用链做个总结:
ContainerBase的start方法:
@Override
public synchronized void start() throws LifecycleException {
if (started)
throw new LifecycleException
(sm.getString("containerBase.alreadyStarted", logName()));
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
addDefaultMapper(this.mapperClass);
started = true;
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
if ((logger != null) && (logger instanceof Lifecycle))
((Lifecycle) logger).start();
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
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();
Mapper mappers[] = findMappers();
for (int i = 0; i < mappers.length; i++) {
if (mappers[i] instanceof Lifecycle)
((Lifecycle) mappers[i]).start();
}
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
}
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
lifecycle.fireLifecycleEvent(START_EVENT, null);
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
StandardContext后面的start方法调用干了啥子,就是上面讲的过程了,这里没有调用其父类ContainerBase的start方法了注意
|