StandardContext
Catalina主要包括Connector和Container,StandardContext就是一个Container,它主要负责对进入的用户请求进行处理。实际来说,不是由它来进行处理,而是交给内部的valve处理。
一个context表示了一个外部应用,它包含多个wrapper,每个wrapper表示一个servlet定义。
/**
* Standard implementation of the <b>Context</b> interface. Each
* child container must be a Wrapper implementation to process the
* requests directed to a particular servlet.
*
* @author Craig R. McClanahan
* @author Remy Maucherat
* @version $Revision: 1.112 $ $Date: 2002/09/09 14:39:37 $
*/
public class StandardContext
extends ContainerBase
implements Context {
// ----------------------------------------------------------- Constructors
/**
* Create a new StandardContext component with the default basic Valve.
*/
public StandardContext() {
super();
pipeline.setBasic(new StandardContextValve());
namingResources.setContainer(this);
}
StandardContext主要成员
/**
* The application available flag for this Context.
*/
private boolean available = false;
/**
* The "correctly configured" flag for this Context.
* context是否已经正确设置完成
*/
private boolean configured = false;
/**
* The document root for this web application.
*/
private String docBase = null;
/**
* The set of filter definitions for this application, keyed by
* filter name.
* 过滤器定义
*/
private HashMap filterDefs = new HashMap();
/**
* The set of filter mappings for this application, in the order
* they were defined in the deployment descriptor.
* 过滤器匹配
*/
private FilterMap filterMaps[] = new FilterMap[0];
/**
* The login configuration descriptor for this web application.
* 登陆权限验证
*/
private LoginConfig loginConfig = null;
/**
* The Java class name of the default Mapper class for this Container.
*/
private String mapperClass =
"org.apache.catalina.core.StandardContextMapper";
/**
* The security role mappings for this application, keyed by role
* name (as used within the application).
* 角色匹配。权限验证用到
*/
private HashMap roleMappings = new HashMap();
/**
* The servlet mappings for this web application, keyed by
* matching pattern.
* servlet匹配。用于根据url等匹配对应servlet
*/
private HashMap servletMappings = new HashMap();
StandardContext.start()
项目启动时,启动Connector和Context,让各种功能就绪。
/**
* 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 {
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");
setLoader(new WebappLoader(this.getClass().getClassLoader()));
} else {
if (debug >= 1)
log("Configuring non-privileged default Loader");
setLoader(new WebappLoader(getParentClassLoader()));
}
}
//manager管理session
if (getManager() == null) { // (3) After prerequisites
if (debug >= 1)
log("Configuring default Manager");
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;
// Start our subordinate components, if any
//启动loader和logger
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();
//启动realm
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 一般指wrapper
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();
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
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)
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);
}
/**
* ******************* 这个是干啥的捏??????************************
* Bind current thread, both for CL purposes and for JNDI ENC support
* during : startup, shutdown and realoading of the context.
*
* @return the previous context class loader
*/
private ClassLoader bindThread() {
ClassLoader oldContextClassLoader =
Thread.currentThread().getContextClassLoader();
if (getResources() == null)
return oldContextClassLoader;
Thread.currentThread().setContextClassLoader
(getLoader().getClassLoader());
DirContextURLStreamHandler.bind(getResources());
if (isUseNaming()) {
try {
ContextBindings.bindThread(this, this);
} catch (NamingException e) {
// Silent catch, as this is a normal case during the early
// startup stages
}
}
return oldContextClassLoader;
}
StandardContext.invoke()
请求进入后,Connector调用context的invoke方法。invoke将请求交给其pipeline去处理,由pipeline中的所有valve顺序处理请求。
/**
* 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);
}
}
reload
总结
StandardContext是比较复杂的一块,像一个大容器,包括了类加载器、session管理、wrapper管理等模块,在启动时顺序启动这些模块。在请求进入时,由这些模块互相合作处理请求。所以start()是比较复杂的,这一块我花了好多时间看,还是不特别理解,只是知道了大致的流程。
StandardContext是Catalina中的一个Container,负责处理用户请求并将其交给内部valve处理。它作为应用程序的容器,包含多个Wrapper,每个对应一个servlet。启动时,通过start()方法准备各种功能,请求到来时,Connector调用invoke()方法,由pipeline中的valve顺序处理。reload功能用于重新加载配置。理解其工作原理需要深入研究start()方法及其涉及的模块协同处理请求的过程。

被折叠的 条评论
为什么被折叠?



