我们首先看下StandardContext的继承关系:
然后查看starndardContext的start方法源码:
public synchronized void start() throwsLifecycleException {
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 defaultResources");
try {
if ((docBase != null)&& (docBase.endsWith(".war")))
setResources(newWARDirContext());
else
setResources(newFileDirContext());
} catch (IllegalArgumentException e) {
log("Error initializingresources: " + e.getMessage());
ok = false;
}
}
if (ok && (resources instanceof ProxyDirContext)) {
DirContext dirContext =
((ProxyDirContext)resources).getDirContext();
if ((dirContext != null)
&& (dirContextinstanceof BaseDirContext)) {
((BaseDirContext)dirContext).setDocBase(getBasePath());
((BaseDirContext)dirContext).allocate();
}
}
if (getLoader() == null) { //(2) Required by Manager
if (getPrivileged()) {
if (debug >= 1)
log("Configuringprivileged default Loader");
setLoader(newWebappLoader(this.getClass().getClassLoader()));
} else {
if (debug >= 1)
log("Configuringnon-privileged default Loader");
setLoader(new WebappLoader(getParentClassLoader()));
}
}
if (getManager() == null) { //(3) After prerequisites
if (debug >= 1)
log("Configuring defaultManager");
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 subordinatecomponents, 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] instanceofLifecycle)
((Lifecycle)mappers[i]).start();
}
// Start our child containers,if any
Container children[] =findChildren();
for (int i = 0; i <children.length; i++) {
if (children[i] instanceofLifecycle)
((Lifecycle)children[i]).start();
}
// Start the Valves in our pipeline(including the basic),
// if any
if (pipeline instanceofLifecycle)
((Lifecycle)pipeline).start();
// Notify our interestedLifecycleListeners
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 standardcontext 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("Startingcompleted");
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);
}
我们看这个start方法的时候,可以结合之前StandardEngine,StandardHost的分析经过来进行剖析:
第一, 利用了lifecycle的监听者模式,我们从digester机制中可以知道,其实调用的就是ContextConfig类的lifecycleEvent方法,这个方法的源码如下:
publicvoid lifecycleEvent(LifecycleEvent event) {
// Identify the context we areassociated with
try {
context = (Context)event.getLifecycle();
if (context instanceofStandardContext) {
int contextDebug = ((StandardContext)context).getDebug();
if (contextDebug >this.debug)
this.debug = contextDebug;
}
} catch (ClassCastException e) {
log(sm.getString("contextConfig.cce", event.getLifecycle()),e);
return;
}
// Process the event that has occurred
if(event.getType().equals(Lifecycle.START_EVENT))
start();
else if(event.getType().equals(Lifecycle.STOP_EVENT))
stop();
}
根据源码可以知道,它再次调用了本类的stat方法:
privatesynchronized void start() {
if (debug > 0)
log(sm.getString("contextConfig.start"));
context.setConfigured(false);
ok = true;
// Set properties based onDefaultContext
Container container =context.getParent();
if( !context.getOverride() ) {
if( container instanceof Host ) {
((Host)container).importDefaultContext(context);
container =container.getParent();
}
if( container instanceof Engine ) {
((Engine)container).importDefaultContext(context);
}
}
// Process the default and applicationweb.xml files
defaultConfig();
applicationConfig();
if (ok) {
validateSecurityRoles();
}
// Scan tag library descriptor filesfor additional listener classes
if (ok) {
try {
tldScan();
} catch (Exception e) {
log(e.getMessage(), e);
ok = false;
}
}
// Configure a certificates exposervalve, if required
if (ok)
certificatesConfig();
// Configure an authenticator if weneed one
if (ok)
authenticatorConfig();
// Dump the contents of this pipelineif requested
if ((debug >= 1) && (contextinstanceof ContainerBase)) {
log("PiplineConfiguration:");
Pipeline pipeline = ((ContainerBase)context).getPipeline();
Valve valves[] = null;
if (pipeline != null)
valves = pipeline.getValves();
if (valves != null) {
for (int i = 0; i <valves.length; i++) {
log(" " + valves[i].getInfo());
}
}
log("======================");
}
// Make our application available if noproblems were encountered
if (ok)
context.setConfigured(true);
else {
log(sm.getString("contextConfig.unavailable"));
context.setConfigured(false);
}
}
在这start方法,我们特别要注意的是defaultConfig和applicationConfig方法,在这2个方法中,其实利用了Digester的机制去解析了我们项目中的web.xml,
private void applicationConfig() {
// Open the application web.xml file, if it exists
InputStream stream = null;
ServletContext servletContext = context.getServletContext();
if (servletContext != null)
stream = servletContext.getResourceAsStream
(Constants.ApplicationWebXml);
if (stream == null) {
log(sm.getString("contextConfig.applicationMissing"));
return;
}
// Process the application web.xml file
synchronized (webDigester) {
try {
URL url =
servletContext.getResource(Constants.ApplicationWebXml);
InputSource is = new InputSource(url.toExternalForm());
is.setByteStream(stream);
webDigester.setDebug(getDebug());
if (context instanceofStandardContext) {
((StandardContext)context).setReplaceWelcomeFiles(true);
}
webDigester.clear();
webDigester.push(context);
webDigester.parse(is);
} catch (SAXParseException e) {
log(sm.getString("contextConfig.applicationParse"), e);
log(sm.getString("contextConfig.applicationPosition",
"" +e.getLineNumber(),
"" +e.getColumnNumber()));
ok = false;
} catch (Exception e) {
log(sm.getString("contextConfig.applicationParse"), e);
ok = false;
} finally {
try {
if (stream != null) {
stream.close();
}
} catch (IOException e) {
log(sm.getString("contextConfig.applicationClose"), e);
}
}
}
}
我们要了解Digester的解析机制,要看看本类的webDigester这个属性的赋值
private static Digester webDigester =createWebDigester();
查看createWebDigesert()方法源码:
private static Digester createWebDigester(){
URL url = null;
Digester webDigester = new Digester();
webDigester.setValidating(true);
url =ContextConfig.class.getResource(Constants.WebDtdResourcePath_22);
webDigester.register(Constants.WebDtdPublicId_22,
url.toString());
url =ContextConfig.class.getResource(Constants.WebDtdResourcePath_23);
webDigester.register(Constants.WebDtdPublicId_23,
url.toString());
webDigester.addRuleSet(newWebRuleSet());
return (webDigester);
}
在这个源码里边,我们主要下webDigester.addRuleSet(newWebRuleSet()); 查看下WebRuleSet类中的addRuleInstances源码
public void addRuleInstances(Digesterdigester) {
digester.addRule(prefix +"web-app",
newSetPublicIdRule(digester, "setPublicId"));
digester.addCallMethod(prefix +"web-app/context-param",
"addParameter",2);
digester.addCallParam(prefix +"web-app/context-param/param-name", 0);
digester.addCallParam(prefix +"web-app/context-param/param-value", 1);
digester.addCallMethod(prefix +"web-app/display-name",
"setDisplayName", 0);
digester.addRule(prefix +"web-app/distributable",
newSetDistributableRule(digester));
digester.addObjectCreate(prefix +"web-app/ejb-local-ref",
"org.apache.catalina.deploy.ContextLocalEjb");
digester.addSetNext(prefix +"web-app/ejb-local-ref",
"addLocalEjb",
"org.apache.catalina.deploy.ContextLocalEjb");
digester.addCallMethod(prefix +"web-app/ejb-local-ref/description",
"setDescription", 0);
digester.addCallMethod(prefix +"web-app/ejb-local-ref/ejb-link",
"setLink", 0);
digester.addCallMethod(prefix +"web-app/ejb-local-ref/ejb-ref-name",
"setName", 0);
digester.addCallMethod(prefix +"web-app/ejb-local-ref/ejb-ref-type",
"setType", 0);
digester.addCallMethod(prefix +"web-app/ejb-local-ref/local",
"setLocal", 0);
digester.addCallMethod(prefix +"web-app/ejb-local-ref/local-home",
"setHome", 0);
digester.addObjectCreate(prefix +"web-app/ejb-ref",
"org.apache.catalina.deploy.ContextEjb");
digester.addSetNext(prefix +"web-app/ejb-ref",
"addEjb",
"org.apache.catalina.deploy.ContextEjb");
digester.addCallMethod(prefix +"web-app/ejb-ref/description",
"setDescription", 0);
digester.addCallMethod(prefix +"web-app/ejb-ref/ejb-link",
"setLink", 0);
digester.addCallMethod(prefix +"web-app/ejb-ref/ejb-ref-name",
"setName", 0);
digester.addCallMethod(prefix +"web-app/ejb-ref/ejb-ref-type",
"setType", 0);
digester.addCallMethod(prefix +"web-app/ejb-ref/home",
"setHome", 0);
digester.addCallMethod(prefix +"web-app/ejb-ref/remote",
"setRemote", 0);
digester.addObjectCreate(prefix +"web-app/env-entry",
"org.apache.catalina.deploy.ContextEnvironment");
digester.addSetNext(prefix +"web-app/env-entry",
"addEnvironment",
"org.apache.catalina.deploy.ContextEnvironment");
digester.addCallMethod(prefix +"web-app/env-entry/description",
"setDescription", 0);
digester.addCallMethod(prefix +"web-app/env-entry/env-entry-name",
"setName", 0);
digester.addCallMethod(prefix +"web-app/env-entry/env-entry-type",
"setType", 0);
digester.addCallMethod(prefix +"web-app/env-entry/env-entry-value",
"setValue", 0);
digester.addObjectCreate(prefix +"web-app/error-page",
"org.apache.catalina.deploy.ErrorPage");
digester.addSetNext(prefix +"web-app/error-page",
"addErrorPage",
"org.apache.catalina.deploy.ErrorPage");
digester.addCallMethod(prefix +"web-app/error-page/error-code",
"setErrorCode", 0);
digester.addCallMethod(prefix +"web-app/error-page/exception-type",
"setExceptionType", 0);
digester.addCallMethod(prefix +"web-app/error-page/location",
"setLocation", 0);
digester.addObjectCreate(prefix +"web-app/filter",
"org.apache.catalina.deploy.FilterDef");
digester.addSetNext(prefix +"web-app/filter",
"addFilterDef",
"org.apache.catalina.deploy.FilterDef");
digester.addCallMethod(prefix +"web-app/filter/description",
"setDescription", 0);
digester.addCallMethod(prefix +"web-app/filter/display-name",
"setDisplayName", 0);
digester.addCallMethod(prefix +"web-app/filter/filter-class",
"setFilterClass", 0);
digester.addCallMethod(prefix +"web-app/filter/filter-name",
"setFilterName", 0);
digester.addCallMethod(prefix +"web-app/filter/large-icon",
"setLargeIcon", 0);
digester.addCallMethod(prefix +"web-app/filter/small-icon",
"setSmallIcon",0);
digester.addCallMethod(prefix +"web-app/filter/init-param",
"addInitParameter", 2);
digester.addCallParam(prefix +"web-app/filter/init-param/param-name",
0);
digester.addCallParam(prefix +"web-app/filter/init-param/param-value",
1);
digester.addObjectCreate(prefix +"web-app/filter-mapping",
"org.apache.catalina.deploy.FilterMap");
digester.addSetNext(prefix +"web-app/filter-mapping",
"addFilterMap",
"org.apache.catalina.deploy.FilterMap");
digester.addCallMethod(prefix +"web-app/filter-mapping/filter-name",
"setFilterName", 0);
digester.addCallMethod(prefix +"web-app/filter-mapping/servlet-name",
"setServletName", 0);
digester.addCallMethod(prefix +"web-app/filter-mapping/url-pattern",
"setURLPattern", 0);
digester.addCallMethod(prefix +"web-app/listener/listener-class",
"addApplicationListener", 0);
digester.addObjectCreate(prefix +"web-app/login-config",
"org.apache.catalina.deploy.LoginConfig");
digester.addSetNext(prefix +"web-app/login-config",
"setLoginConfig",
"org.apache.catalina.deploy.LoginConfig");
digester.addCallMethod(prefix +"web-app/login-config/auth-method",
"setAuthMethod", 0);
digester.addCallMethod(prefix +"web-app/login-config/realm-name",
"setRealmName", 0);
digester.addCallMethod(prefix +"web-app/login-config/form-login-config/form-error-page",
"setErrorPage", 0);
digester.addCallMethod(prefix +"web-app/login-config/form-login-config/form-login-page",
"setLoginPage", 0);
digester.addCallMethod(prefix +"web-app/mime-mapping",
"addMimeMapping", 2);
digester.addCallParam(prefix +"web-app/mime-mapping/extension", 0);
digester.addCallParam(prefix +"web-app/mime-mapping/mime-type", 1);
digester.addCallMethod(prefix +"web-app/resource-env-ref",
"addResourceEnvRef", 2);
digester.addCallParam(prefix +"web-app/resource-env-ref/resource-env-ref-name", 0);
digester.addCallParam(prefix +"web-app/resource-env-ref/resource-env-ref-type", 1);
digester.addObjectCreate(prefix +"web-app/resource-ref",
"org.apache.catalina.deploy.ContextResource");
digester.addSetNext(prefix +"web-app/resource-ref",
"addResource",
"org.apache.catalina.deploy.ContextResource");
digester.addCallMethod(prefix +"web-app/resource-ref/description",
"setDescription", 0);
digester.addCallMethod(prefix +"web-app/resource-ref/res-auth",
"setAuth", 0);
digester.addCallMethod(prefix +"web-app/resource-ref/res-ref-name",
"setName", 0);
digester.addCallMethod(prefix +"web-app/resource-ref/res-sharing-scope",
"setScope", 0);
digester.addCallMethod(prefix +"web-app/resource-ref/res-type",
"setType", 0);
digester.addObjectCreate(prefix +"web-app/security-constraint",
"org.apache.catalina.deploy.SecurityConstraint");
digester.addSetNext(prefix +"web-app/security-constraint",
"addConstraint",
"org.apache.catalina.deploy.SecurityConstraint");
digester.addRule(prefix +"web-app/security-constraint/auth-constraint",
new SetAuthConstraintRule(digester));
digester.addCallMethod(prefix +"web-app/security-constraint/auth-constraint/role-name",
"addAuthRole", 0);
digester.addCallMethod(prefix +"web-app/security-constraint/display-name",
"setDisplayName", 0);
digester.addCallMethod(prefix +"web-app/security-constraint/user-data-constraint/transport-guarantee",
"setUserConstraint", 0);
digester.addObjectCreate(prefix +"web-app/security-constraint/web-resource-collection",
"org.apache.catalina.deploy.SecurityCollection");
digester.addSetNext(prefix +"web-app/security-constraint/web-resource-collection",
"addCollection",
"org.apache.catalina.deploy.SecurityCollection");
digester.addCallMethod(prefix +"web-app/security-constraint/web-resource-collection/http-method",
"addMethod", 0);
digester.addCallMethod(prefix +"web-app/security-constraint/web-resource-collection/url-pattern",
"addPattern", 0);
digester.addCallMethod(prefix +"web-app/security-constraint/web-resource-collection/web-resource-name",
"setName", 0);
digester.addCallMethod(prefix +"web-app/security-role/role-name",
"addSecurityRole", 0);
digester.addRule(prefix +"web-app/servlet",
newWrapperCreateRule(digester));
digester.addSetNext(prefix +"web-app/servlet",
"addChild",
"org.apache.catalina.Container");
digester.addCallMethod(prefix +"web-app/servlet/init-param",
"addInitParameter", 2);
digester.addCallParam(prefix +"web-app/servlet/init-param/param-name",
0);
digester.addCallParam(prefix +"web-app/servlet/init-param/param-value",
1);
digester.addCallMethod(prefix +"web-app/servlet/jsp-file",
"setJspFile",0);
digester.addCallMethod(prefix +"web-app/servlet/load-on-startup",
"setLoadOnStartupString", 0);
digester.addCallMethod(prefix +"web-app/servlet/run-as/role-name",
"setRunAs",0);
digester.addCallMethod(prefix +"web-app/servlet/security-role-ref",
"addSecurityReference", 2);
digester.addCallParam(prefix +"web-app/servlet/security-role-ref/role-link", 1);
digester.addCallParam(prefix +"web-app/servlet/security-role-ref/role-name", 0);
digester.addCallMethod(prefix +"web-app/servlet/servlet-class",
"setServletClass", 0);
digester.addCallMethod(prefix +"web-app/servlet/servlet-name",
"setName", 0);
digester.addCallMethod(prefix +"web-app/servlet-mapping",
"addServletMapping", 2);
digester.addCallParam(prefix +"web-app/servlet-mapping/servlet-name", 1);
digester.addCallParam(prefix +"web-app/servlet-mapping/url-pattern", 0);
digester.addCallMethod(prefix +"web-app/session-config/session-timeout",
"setSessionTimeout", 1,
new Class[] {Integer.TYPE });
digester.addCallParam(prefix +"web-app/session-config/session-timeout", 0);
digester.addCallMethod(prefix +"web-app/taglib",
"addTaglib", 2);
digester.addCallParam(prefix +"web-app/taglib/taglib-location", 1);
digester.addCallParam(prefix +"web-app/taglib/taglib-uri", 0);
digester.addCallMethod(prefix +"web-app/welcome-file-list/welcome-file",
"addWelcomeFile",0);
}
}
这个时候,我们就可以知道,原来对web.xml的解析就在这里实现的啦!
但是这个时候,我们还要特别注意下,
digester.addRule(prefix+ "web-app/servlet",
newWrapperCreateRule(digester));
在查看下WrapperCreateRule类中的begin方法
public voidbegin(Attributes attributes) throws Exception {
Context context =
(Context)digester.peek(digester.getCount() - 1);
Wrapper wrapper =context.createWrapper();
digester.push(wrapper);
if (digester.getDebug() > 0)
digester.log("new " +wrapper.getClass().getName());
}
我们可以知道,Wrapperwrapper = context.createWrapper();调用了context的createWrapper方法,而这个context的实现类就是我们的standardContext,我们可以返回到
standardContext中查看createWrapper
public Wrapper createWrapper() {
Wrapper wrapper = new StandardWrapper();
synchronized (instanceListeners) {
for (int i = 0; i < instanceListeners.length; i++) {
try {
Class clazz =Class.forName(instanceListeners[i]);
InstanceListener listener =
(InstanceListener)clazz.newInstance();
wrapper.addInstanceListener(listener);
} catch (Throwable t) {
log("createWrapper", t);
return (null);
}
}
}
synchronized (wrapperLifecycles) {
for (int i = 0; i < wrapperLifecycles.length; i++) {
try {
Class clazz =Class.forName(wrapperLifecycles[i]);
LifecycleListener listener=
(LifecycleListener)clazz.newInstance();
if (wrapper instanceofLifecycle)
((Lifecycle)wrapper).addLifecycleListener(listener);
} catch (Throwable t) {
log("createWrapper", t);
return (null);
}
}
}
synchronized (wrapperListeners) {
for (int i = 0; i < wrapperListeners.length; i++) {
try {
Class clazz =Class.forName(wrapperListeners[i]);
ContainerListener listener=
(ContainerListener)clazz.newInstance();
wrapper.addContainerListener(listener);
} catch (Throwable t) {
log("createWrapper", t);
return (null);
}
}
}
return (wrapper);
}
明白这里返回了wrapper的实现类StandardWrapper的对象
从上述的分析可以知道,在standardContext启动的时候,通过监听者模式,将项目部署文件web.xml文件进行解析,并利用包装类standardWrapper将web.xml文件中的servlet进行包装起来,一个servlet对应一个standardWrapper
第二点,addDefaultMapper使用了StandardContextMapper
第三点,执行了children里边的start方法,children里边的元素怎么设置进去的呢?
我们查看下WebRuleSet类中的:
digester.addRule(prefix +"web-app/servlet",
newWrapperCreateRule(digester));
digester.addSetNext(prefix + "web-app/servlet",
"addChild",
"org.apache.catalina.Container");
就很清楚了,children其实就是包装了servlet的standardWrapper,也就是你说standardContext的启动,移交给了starndardWrapper启动
第四点,其他操作我们目前暂时略过
我们standardContext的启动流程图:
standardContext启动的关系类图: