Tomcat 中的 Context
- Context 定义内容太多代码就不贴了,自己看源码
- 从 Context 的方法可以看出很多都是关于 web 方面的
- Context 实现了 Container 接口和 ContextBind 接口
- Context 的实现类是 StandardContext
StandardContext 的构造方法
public StandardContext() {
super();
pipeline.setBasic(new StandardContextValve());
broadcaster = new NotificationBroadcasterSupport();
if (!Globals.STRICT_SERVLET_COMPLIANCE) {
resourceOnlyServlets.add("jsp");
}
}
StandardContext 的 initInternal 方法
protected void initInternal() throws LifecycleException {
super.initInternal();
if (namingResources != null) {
namingResources.init();
}
if (this.getObjectName() != null) {
Notification notification = new Notification("j2ee.object.created",
this.getObjectName(), sequenceNumber.getAndIncrement());
broadcaster.sendNotification(notification);
}
}
Standard 的 startInternal 方法
protected synchronized void startInternal() throws LifecycleException {
if(log.isDebugEnabled())
log.debug("Starting " + getBaseName());
if (this.getObjectName() != null) {
Notification notification = new Notification("j2ee.state.starting",
this.getObjectName(), sequenceNumber.getAndIncrement());
broadcaster.sendNotification(notification);
}
setConfigured(false);
boolean ok = true;
if (namingResources != null) {
namingResources.start();
}
postWorkDirectory();
if (getResources() == null) {
if (log.isDebugEnabled())
log.debug("Configuring default Resources");
try {
setResources(new StandardRoot(this));
} catch (IllegalArgumentException e) {
log.error(sm.getString("standardContext.resourcesInit"), e);
ok = false;
}
}
if (ok) {
resourcesStart();
}
if (getLoader() == null) {
WebappLoader webappLoader = new WebappLoader();
webappLoader.setDelegate(getDelegate());
setLoader(webappLoader);
}
if (cookieProcessor == null) {
cookieProcessor = new Rfc6265CookieProcessor();
}
getCharsetMapper();
boolean dependencyCheck = true;
try {
dependencyCheck = ExtensionValidator.validateApplication
(getResources(), this);
} catch (IOException ioe) {
log.error(sm.getString("standardContext.extensionValidationError"), ioe);
dependencyCheck = false;
}
if (!dependencyCheck) {
ok = false;
}
String useNamingProperty = System.getProperty("catalina.useNaming");
if ((useNamingProperty != null)
&& (useNamingProperty.equals("false"))) {
useNaming = false;
}
if (ok && isUseNaming()) {
if (getNamingContextListener() == null) {
NamingContextListener ncl = new NamingContextListener();
ncl.setName(getNamingContextName());
ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite());
addLifecycleListener(ncl);
setNamingContextListener(ncl);
}
}
if (log.isDebugEnabled())
log.debug("Processing standard container startup");
ClassLoader oldCCL = bindThread();
try {
if (ok) {
Loader loader = getLoader();
if (loader instanceof Lifecycle) {
((Lifecycle) loader).start();
}
setClassLoaderProperty("clearReferencesRmiTargets",
getClearReferencesRmiTargets());
setClassLoaderProperty("clearReferencesStopThreads",
getClearReferencesStopThreads());
setClassLoaderProperty("clearReferencesStopTimerThreads",
getClearReferencesStopTimerThreads());
setClassLoaderProperty("clearReferencesHttpClientKeepAliveThread",
getClearReferencesHttpClientKeepAliveThread());
setClassLoaderProperty("clearReferencesObjectStreamClassCaches",
getClearReferencesObjectStreamClassCaches());
setClassLoaderProperty("clearReferencesThreadLocals",
getClearReferencesThreadLocals());
unbindThread(oldCCL);
oldCCL = bindThread();
logger = null;
getLogger();
Realm realm = getRealmInternal();
if(null != realm) {
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}
CredentialHandler safeHandler = new CredentialHandler() {
@Override
public boolean matches(String inputCredentials, String storedCredentials) {
return getRealmInternal().getCredentialHandler().matches(inputCredentials, storedCredentials);
}
@Override
public String mutate(String inputCredentials) {
return getRealmInternal().getCredentialHandler().mutate(inputCredentials);
}
};
context.setAttribute(Globals.CREDENTIAL_HANDLER, safeHandler);
}
fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
for (Container child : findChildren()) {
if (!child.getState().isAvailable()) {
child.start();
}
}
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
Manager contextManager = null;
Manager manager = getManager();
if (manager == null) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("standardContext.cluster.noManager",
Boolean.valueOf((getCluster() != null)),
Boolean.valueOf(distributable)));
}
if ((getCluster() != null) && distributable) {
try {
contextManager = getCluster().createManager(getName());
} catch (Exception ex) {
log.error("standardContext.clusterFail", ex);
ok = false;
}
} else {
contextManager = new StandardManager();
}
}
if (contextManager != null) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("standardContext.manager",
contextManager.getClass().getName()));
}
setManager(contextManager);
}
if (manager!=null && (getCluster() != null) && distributable) {
getCluster().registerManager(manager);
}
}
if (!getConfigured()) {
log.error(sm.getString("standardContext.configurationFail"));
ok = false;
}
if (ok) {
getServletContext().setAttribute
(Globals.RESOURCES_ATTR, getResources());
if (getInstanceManager() == null) {
javax.naming.Context context = null;
if (isUseNaming() && getNamingContextListener() != null) {
context = getNamingContextListener().getEnvContext();
}
Map<String, Map<String, String>> injectionMap = buildInjectionMap(
getIgnoreAnnotations() ? new NamingResourcesImpl(): getNamingResources());
setInstanceManager(new DefaultInstanceManager(context,
injectionMap, this, this.getClass().getClassLoader()));
}
getServletContext().setAttribute(
InstanceManager.class.getName(), getInstanceManager());
InstanceManagerBindings.bind(getLoader().getClassLoader(), getInstanceManager());
getServletContext().setAttribute(
JarScanner.class.getName(), getJarScanner());
getServletContext().setAttribute(Globals.WEBAPP_VERSION, getWebappVersion());
}
mergeParameters();
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
initializers.entrySet()) {
try {
entry.getKey().onStartup(entry.getValue(),
getServletContext());
} catch (ServletException e) {
log.error(sm.getString("standardContext.sciFail"), e);
ok = false;
break;
}
}
if (ok) {
if (!listenerStart()) {
log.error(sm.getString("standardContext.listenerFail"));
ok = false;
}
}
if (ok) {
checkConstraintsForUncoveredMethods(findConstraints());
}
try {
Manager manager = getManager();
if (manager instanceof Lifecycle) {
((Lifecycle) manager).start();
}
} catch(Exception e) {
log.error(sm.getString("standardContext.managerFail"), e);
ok = false;
}
if (ok) {
if (!filterStart()) {
log.error(sm.getString("standardContext.filterFail"));
ok = false;
}
}
if (ok) {
if (!loadOnStartup(findChildren())){
log.error(sm.getString("standardContext.servletFail"));
ok = false;
}
}
super.threadStart();
} finally {
unbindThread(oldCCL);
}
if (ok) {
if (log.isDebugEnabled())
log.debug("Starting completed");
} else {
log.error(sm.getString("standardContext.startFailed", getName()));
}
startTime=System.currentTimeMillis();
if (ok && (this.getObjectName() != null)) {
Notification notification =
new Notification("j2ee.state.running", this.getObjectName(),
sequenceNumber.getAndIncrement());
broadcaster.sendNotification(notification);
}
getResources().gc();
if (!ok) {
setState(LifecycleState.FAILED);
} else {
setState(LifecycleState.STARTING);
}
}
StandardContext 的 stopInternal 方法
protected synchronized void stopInternal() throws LifecycleException {
if (this.getObjectName() != null) {
Notification notification =
new Notification("j2ee.state.stopping", this.getObjectName(),
sequenceNumber.getAndIncrement());
broadcaster.sendNotification(notification);
}
long limit = System.currentTimeMillis() + unloadDelay;
while (inProgressAsyncCount.get() > 0 && System.currentTimeMillis() < limit) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
log.info(sm.getString("standardContext.stop.asyncWaitInterrupted"), e);
break;
}
}
setState(LifecycleState.STOPPING);
ClassLoader oldCCL = bindThread();
try {
final Container[] children = findChildren();
threadStop();
for (int i = 0; i < children.length; i++) {
children[i].stop();
}
filterStop();
Manager manager = getManager();
if (manager instanceof Lifecycle && ((Lifecycle) manager).getState().isAvailable()) {
((Lifecycle) manager).stop();
}
listenerStop();
setCharsetMapper(null);
if (log.isDebugEnabled())
log.debug("Processing standard container shutdown");
if (namingResources != null) {
namingResources.stop();
}
fireLifecycleEvent(Lifecycle.CONFIGURE_STOP_EVENT, null);
if (pipeline instanceof Lifecycle &&
((Lifecycle) pipeline).getState().isAvailable()) {
((Lifecycle) pipeline).stop();
}
if (context != null)
context.clearAttributes();
Realm realm = getRealmInternal();
if (realm instanceof Lifecycle) {
((Lifecycle) realm).stop();
}
Loader loader = getLoader();
if (loader instanceof Lifecycle) {
ClassLoader classLoader = loader.getClassLoader();
((Lifecycle) loader).stop();
if (classLoader != null) {
InstanceManagerBindings.unbind(classLoader);
}
}
resourcesStop();
} finally {
unbindThread(oldCCL);
}
if (this.getObjectName() != null) {
Notification notification =
new Notification("j2ee.state.stopped", this.getObjectName(),
sequenceNumber.getAndIncrement());
broadcaster.sendNotification(notification);
}
context = null;
try {
resetContext();
} catch( Exception ex ) {
log.error( "Error resetting context " + this + " " + ex, ex );
}
setInstanceManager(null);
if (log.isDebugEnabled())
log.debug("Stopping complete");
}
StandardContext 的 destroyInternal 方法
protected void destroyInternal() throws LifecycleException {
if (getObjectName() != null) {
Notification notification =
new Notification("j2ee.object.deleted", this.getObjectName(),
sequenceNumber.getAndIncrement());
broadcaster.sendNotification(notification);
}
if (namingResources != null) {
namingResources.destroy();
}
Loader loader = getLoader();
if (loader instanceof Lifecycle) {
((Lifecycle) loader).destroy();
}
Manager manager = getManager();
if (manager instanceof Lifecycle) {
((Lifecycle) manager).destroy();
}
if (resources != null) {
resources.destroy();
}
super.destroyInternal();
}
StandardContext 中的基础阀 -- StandardContextValve
public final void invoke(Request request, Response response)
throws IOException, ServletException {
MessageBytes requestPathMB = request.getRequestPathMB();
if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
|| (requestPathMB.equalsIgnoreCase("/META-INF"))
|| (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
|| (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
Wrapper wrapper = request.getWrapper();
if (wrapper == null || wrapper.isUnavailable()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
try {
response.sendAcknowledgement();
} catch (IOException ioe) {
container.getLogger().error(sm.getString(
"standardContextValve.acknowledgeException"), ioe);
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
}
wrapper.getPipeline().getFirst().invoke(request, response);
}
小结
- Context 中有大量的 web 方面的方法,这里只看启动流程