2013-10-06
是org.apache.catalina.Context的标准实现,继承自ContainerBase基容器,具备容器的功能,在tomcat结构层次图中位于Host内部,包含ServletWrapper容器,它的角色是管理在其内部的ServletWrapper,从Host那里接收请求信息,加载实例化Servlet,然后选择一个合适的ServletWrapper处理,同一个Context内部中Servlet数据共享,不同Context之间数据隔离。在Context层面上,Filter的作用就出来了,Filter是用来过滤Servlet的组件,Context负责在每个Servlet上面调用Filter过滤,Context与开发Servlet息息相关,跟前面的几个组件相比,Context能够提供更多的信息给Servlet。一个webapp有一个Context,Context负责管理在其内部的组件:Servlet,Cookie,Session等等。
Context
tomcat定义的Servlet上下文接口,也即一个webapp的应用环境。tomcat定义了一个Context所必须具备的功能,定义对Cookie,Session,ServletWrapper等组件的管理,为一个请求选项合适的Servlet方法,他要解决的问题是为请求选择Servlet,Servlet之间的数据共享问题。
ContainerBase
容器基类,StandardContext继承该类,具备了基容器的功能和方法。
StandardContext()
默认构造器,设定basicValve, 初始化NotificationBroadcasterSupport,用户支持j2ee企业功能。
StandardContextValve
Context的标准BasicValve,作用连接Context和ServletWrapper的工具。StandardContextValve主要完成的功能是:
URLEncoder
跟URL相关,具有对URL编码的功能,替换特殊字符功能。
charsetMapper : CharsetMapper
Context多支持的字符集,跟本地化有关,负责处理本地字符问题。
context : ApplicationContext
Servlet的上下文,一个wepapp中提供一个全局的servlet上下,提供了一些列的访问资源的接口,servlet通过ApplicationContext获取servlet的运行环境信息,加载资源,获取资源。与StandardContext的作用是相辅相成的关系,两种的角色不同,ApplicationContext负责的是servlet运行环境上下信息,不关心session管理,cookie管理,servlet的加载,servlet的选择问题,请求信息,一句话就是:他是servlet管家。StandardContext需要负责管理session,Cookie,Servlet的加载和卸载,负责请求信息的处理,掌握控制权,他是servlet的爹妈。
exceptionPages : HashMap
错误页面信息匹配,对于404,403等HTTP错误码,tomcat通过映射页面来定制提示信息。
filterConfigs : HashMap
k/v的方式保存Filter与Fifter配置信息,在过滤请求信息是使用到。
filterDefs : HashMap
k/v的方式保存Filter与Filter的定义信息。
filterMaps : FilterMap[]
webapp中所有的Filter集合。别名映射关系。
mapper : Mapper
Servlet与访问url匹配集合。
namingContextListener : NamingContextListener
是JNDI中的内容,不了解,比较复杂,只知道是负责监听javax.naming.Context资源事件。NamingContextListener实现了LifecycleListener、ContainerListener、PropertyChangeListener3个接口,具备监听Lifecycle组件,Container组件、PropertyChange的事件能力。
namingResources : NamingResources
是JNDI中的内容,不了解,比较复杂,知道它管理命名资源,将要加载的资源封装成对象,可以直接从NamingResources获取对象了。
servletMappings : HashMap
访问url匹配与Servlet类映射。
wrapperClassName : String
用来处理Servlet包装的Wrapper类类名,负责加载管理Servlet。
wrapperClass : Class
用来处理Servlet包装的Wrapper类,负责加载管理Servlet。
addServletMapping(String, String, boolean)
添加servlet和url模式映射关系。从web.xml或者注解中获取Servlet与url的关系,然后保存到Context中。
createWrapper()
实例化Wrapper类,创建一个容纳Servlet的容器,并在Wrapper上注册监听器。主要完成以下步骤:
/**
* Factory method to create and return a new Wrapper instance, of the Java
* implementation class appropriate for this Context implementation. The
* constructor of the instantiated Wrapper will have been called, but no
* properties will have been set.
*/
public Wrapper createWrapper() {
Wrapper wrapper = null;
if (wrapperClass != null) {
try {
wrapper = (Wrapper) wrapperClass.newInstance();
} catch (Throwable t) {
log.error("createWrapper", t);
return (null);
}
} else {
wrapper = new StandardWrapper();
}
synchronized (instanceListenersLock) {
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.error("createWrapper", t);
return (null);
}
}
}
synchronized (wrapperLifecyclesLock) {
for (int i = 0; i < wrapperLifecycles.length; i++) {
try {
Class clazz = Class.forName(wrapperLifecycles[i]);
LifecycleListener listener = (LifecycleListener) clazz
.newInstance();
if (wrapper instanceof Lifecycle)
((Lifecycle) wrapper).addLifecycleListener(listener);
} catch (Throwable t) {
log.error("createWrapper", t);
return (null);
}
}
}
synchronized (wrapperListenersLock) {
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.error("createWrapper", t);
return (null);
}
}
}
return (wrapper);
}
reload()
重新加载数据,用于当类或者配置文件发送变化时重新加载,从代码中可以看出来,tomcat是通过重启来完成的,主要有几个步骤
filterStart()
配置和初始化过滤Servlet的Filter集合。
filterStop()
释放和清除Filter集合配置。
listenerStart()
配置并实例化注册在Context上的监听器集合,用于监听在Context上面触发的事件,监听器用于监听Conext事件和Servlet事件。分下面几个步骤:
/**
* Configure the set of instantiated application event listeners for this
* Context. Return <code>true</code> if all listeners wre initialized
* successfully, or <code>false</code> otherwise.
*/
public boolean listenerStart() {
if (log.isDebugEnabled())
log.debug("Configuring application event listeners");
// Instantiate the required listeners
//取当前Context的类加载器,用于实例化监听器需要。不同Context的类加载可能不同,出于安全考虑
ClassLoader loader = getLoader().getClassLoader();
String listeners[] = findApplicationListeners();
Object results[] = new Object[listeners.length];
boolean ok = true;
//遍历所有监听器,并实例化到results列表中
for (int i = 0; i < results.length; i++) {
if (getLogger().isDebugEnabled())
getLogger().debug(
" Configuring event listener class '" + listeners[i]
+ "'");
try {
Class clazz = loader.loadClass(listeners[i]);
results[i] = clazz.newInstance();
// Annotation processing
if (!getIgnoreAnnotations()) {
getAnnotationProcessor().processAnnotations(results[i]);
getAnnotationProcessor().postConstruct(results[i]);
}
} catch (Throwable t) {
getLogger().error(
sm.getString("standardContext.applicationListener",
listeners[i]), t);
ok = false;
}
}
if (!ok) {
getLogger().error(
sm.getString("standardContext.applicationSkipped"));
return (false);
}
// Sort listeners in two arrays
ArrayList eventListeners = new ArrayList();
ArrayList lifecycleListeners = new ArrayList();
//遍历监听器,区分ContextEvent监听器和LifecycleEvent监听器
for (int i = 0; i < results.length; i++) {
if ((results[i] instanceof ServletContextAttributeListener)
|| (results[i] instanceof ServletRequestAttributeListener)
|| (results[i] instanceof ServletRequestListener)
|| (results[i] instanceof HttpSessionAttributeListener)) {
eventListeners.add(results[i]);
}
if ((results[i] instanceof ServletContextListener)
|| (results[i] instanceof HttpSessionListener)) {
lifecycleListeners.add(results[i]);
}
}
//注册监听器
setApplicationEventListeners(eventListeners.toArray());
//注册监听器
setApplicationLifecycleListeners(lifecycleListeners.toArray());
// Send application start events
if (getLogger().isDebugEnabled())
getLogger().debug("Sending application start events");
Object instances[] = getApplicationLifecycleListeners();
if (instances == null)
return (ok);
ServletContextEvent event = new ServletContextEvent(getServletContext());
//触发Context实例化事件,通知监听
for (int i = 0; i < instances.length; i++) {
if (instances[i] == null)
continue;
if (!(instances[i] instanceof ServletContextListener))
continue;
ServletContextListener listener = (ServletContextListener) instances[i];
try {
fireContainerEvent("beforeContextInitialized", listener);
listener.contextInitialized(event);
fireContainerEvent("afterContextInitialized", listener);
} catch (Throwable t) {
fireContainerEvent("afterContextInitialized", listener);
getLogger().error(
sm.getString("standardContext.listenerStart",
instances[i].getClass().getName()), t);
ok = false;
}
}
return (ok);
}
listenerStop()
在Conext上停止监听器的监听,步骤与启动时相反,首先触发停止监听事件,然后再清除资源。
resourcesStart()
分配Context的目录资源,这里涉及到目录服务。
resourcesStop()
停止Context的目录资源,这里涉及到目录服务。
loadOnStartup(Container[])
这个方法是用来处理在web.xml中配置的loadonstartup Servlet,需要在Context启动时加载实例化,而不是要等待请求触发才实例化。特殊servlet提前实例化加快了第一次访问速度。主要有两个步骤:
/**
* 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;
Integer key = Integer.valueOf(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) {
getLogger()
.error(sm.getString(
"standardWrapper.loadException", getName()),
StandardWrapper.getRootCause(e));
// NOTE: load errors (including a servlet that throws
// UnavailableException from tht init() method) are NOT
// fatal to application startup
}
}
}
}
init()
负责初始化Context,为Context启动做准备工作。在方法中完成了Context配置类的实例化,并将其注册到生命周期监听器集合中,调用父类初始化函数super.init(),然后出发初始化事件。
start()
负责启动Context,启动web app应用,在启动方法中要完成很多步骤:
/**
* Start this Context component.
*
* @exception LifecycleException
* if a startup error occurs
*/
public synchronized void start() throws LifecycleException {
// if (lazy ) return;
if (started) {
if (log.isInfoEnabled())
log.info(sm
.getString("containerBase.alreadyStarted", logName()));
return;
}
if (!initialized) {
try {
init();
} catch (Exception ex) {
throw new LifecycleException("Error initializaing ", ex);
}
}
if (log.isDebugEnabled())
log.debug("Starting " + ("".equals(getName()) ? "ROOT" : getName()));
// Set JMX object name for proper pipeline registration
preRegisterJMX();
if ((oname != null)
&& (Registry.getRegistry(null, null).getMBeanServer()
.isRegistered(oname))) {
// As things depend on the JMX registration, the context
// must be reregistered again once properly initialized
Registry.getRegistry(null, null).unregisterComponent(oname);
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
setAvailable(false);
setConfigured(false);
boolean ok = true;
// Add missing components as necessary
if (webappResources == null) { // (1) Required by Loader
if (log.isDebugEnabled())
log.debug("Configuring default Resources");
try {
if ((docBase != null) && (docBase.endsWith(".war"))
&& (!(new File(getBasePath())).isDirectory()))
setResources(new WARDirContext());
else
setResources(new FileDirContext());
} catch (IllegalArgumentException e) {
log.error("Error initializing resources: " + e.getMessage());
ok = false;
}
}
if (ok) {
if (!resourcesStart()) {
log.error("Error in resourceStart()");
ok = false;
}
}
// Look for a realm - that may have been configured earlier.
// If the realm is added after context - it'll set itself.
// TODO: what is the use case for this ?
if (realm == null && mserver != null) {
ObjectName realmName = null;
try {
realmName = new ObjectName(getEngineName()
+ ":type=Realm,host=" + getHostname() + ",path="
+ getPath());
if (mserver.isRegistered(realmName)) {
mserver.invoke(realmName, "init", new Object[] {},
new String[] {});
}
} catch (Throwable t) {
if (log.isDebugEnabled())
log.debug("No realm for this host " + realmName);
}
}
if (getLoader() == null) {
WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
webappLoader.setDelegate(getDelegate());
setLoader(webappLoader);
}
// Initialize character set mapper
getCharsetMapper();
// Post work directory
postWorkDirectory();
// Validate required extensions
boolean dependencyCheck = true;
try {
dependencyCheck = ExtensionValidator.validateApplication(
getResources(), this);
} catch (IOException ioe) {
log.error("Error in dependencyCheck", ioe);
dependencyCheck = false;
}
if (!dependencyCheck) {
// do not make application available if depency check fails
ok = false;
}
// 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.setName(getNamingContextName());
addLifecycleListener(namingContextListener);
}
}
// Standard container startup
if (log.isDebugEnabled())
log.debug("Processing standard container startup");
// Binding thread
ClassLoader oldCCL = bindThread();
boolean mainOk = false;
try {
if (ok) {
started = true;
// Start our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
// since the loader just started, the webapp classloader is now
// created.
// By calling unbindThread and bindThread in a row, we setup the
// current Thread CCL to be the webapp classloader
unbindThread(oldCCL);
oldCCL = bindThread();
// Initialize logger again. Other components might have used it
// too early,
// so it should be reset.
logger = null;
getLogger();
if ((logger != null) && (logger instanceof Lifecycle))
((Lifecycle) logger).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();
// 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();
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
// Acquire clustered manager
Manager contextManager = null;
if (manager == null) {
if ((getCluster() != null) && distributable) {
try {
contextManager = getCluster().createManager(
getName());
} catch (Exception ex) {
log.error("standardContext.clusterFail", ex);
ok = false;
}
} else {
contextManager = new StandardManager();
}
}
// Configure default manager if none was specified
if (contextManager != null) {
setManager(contextManager);
}
if (manager != null && (getCluster() != null) && distributable) {
// let the cluster know that there is a context that is
// distributable
// and that it has its own manager
getCluster().registerManager(manager);
}
mainOk = true;
}
} finally {
// Unbinding thread
unbindThread(oldCCL);
if (!mainOk) {
// An exception occurred
// Register with JMX anyway, to allow management
registerJMX();
}
}
if (!getConfigured()) {
log.error("Error getConfigured");
ok = false;
}
// We put the resources into the servlet context
if (ok)
getServletContext().setAttribute(Globals.RESOURCES_ATTR,
getResources());
// Initialize associated mapper
mapper.setContext(getPath(), welcomeFiles, resources);
// Binding thread
oldCCL = bindThread();
// Set annotation processing parameter for Jasper (unfortunately, since
// this can be configured in many places and not just in
// /WEB-INF/web.xml,
// there are not many solutions)
// Initialize annotation processor
if (ok && !getIgnoreAnnotations()) {
if (annotationProcessor == null) {
if (isUseNaming() && namingContextListener != null) {
annotationProcessor = new DefaultAnnotationProcessor(
namingContextListener.getEnvContext());
} else {
annotationProcessor = new DefaultAnnotationProcessor(null);
}
}
getServletContext().setAttribute(
AnnotationProcessor.class.getName(), annotationProcessor);
}
try {
// Create context attributes that will be required
if (ok) {
postWelcomeFiles();
}
// Set up the context init params
mergeParameters();
if (ok) {
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
// Configure and call application event listeners
if (ok) {
if (!listenerStart()) {
log.error("Error listenerStart");
ok = false;
}
}
try {
// Start manager
if ((manager != null) && (manager instanceof Lifecycle)) {
((Lifecycle) getManager()).start();
}
// Start ContainerBackgroundProcessor thread
super.threadStart();
} catch (Exception e) {
log.error("Error manager.start()", e);
ok = false;
}
// Configure and call application filters
if (ok) {
if (!filterStart()) {
log.error("Error filterStart");
ok = false;
}
}
// Load and initialize all "load on startup" servlets
if (ok) {
loadOnStartup(findChildren());
}
} finally {
// Unbinding thread
unbindThread(oldCCL);
}
// Set available status depending upon startup success
if (ok) {
if (log.isDebugEnabled())
log.debug("Starting completed");
setAvailable(true);
} else {
log.error(sm.getString("standardContext.startFailed", getName()));
try {
stop();
} catch (Throwable t) {
log.error(sm.getString("standardContext.startCleanup"), t);
}
setAvailable(false);
}
// JMX registration
registerJMX();
startTime = System.currentTimeMillis();
// Send j2ee.state.running notification
if (ok && (this.getObjectName() != null)) {
Notification notification = new Notification("j2ee.state.running",
this.getObjectName(), sequenceNumber++);
broadcaster.sendNotification(notification);
}
// Close all JARs right away to avoid always opening a peak number
// of files on startup
if (getLoader() instanceof WebappLoader) {
((WebappLoader) getLoader()).closeJARs(true);
}
// Reinitializing if something went wrong
if (!ok && started) {
stop();
}
// cacheContext();
}
cacheContext()
缓存Context对象,将对象序列化到本地文件中。
mergeParameters()
合并Context初始化参数配置
stop()
负责停止Context,清理Context中组件的状态,以启动Context的顺序到这来:
/**
* Stop this Context component.
*
* @exception LifecycleException
* if a shutdown error occurs
*/
public synchronized void stop() throws LifecycleException {
// Validate and update our current component state
if (!started) {
if (log.isInfoEnabled())
log.info(sm.getString("containerBase.notStarted", logName()));
return;
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
// Send j2ee.state.stopping notification
if (this.getObjectName() != null) {
Notification notification = new Notification("j2ee.state.stopping",
this.getObjectName(), sequenceNumber++);
broadcaster.sendNotification(notification);
}
// Mark this application as unavailable while we shut down
setAvailable(false);
// Binding thread
ClassLoader oldCCL = bindThread();
try {
// Stop our child containers, if any
Container[] children = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).stop();
}
// Stop our filters
filterStop();
// Stop ContainerBackgroundProcessor thread
super.threadStop();
if ((manager != null) && (manager instanceof Lifecycle)) {
((Lifecycle) manager).stop();
}
// Stop our application listeners
listenerStop();
// Finalize our character set mapper
setCharsetMapper(null);
// Normal container shutdown processing
if (log.isDebugEnabled())
log.debug("Processing standard container shutdown");
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
// Stop the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).stop();
}
// Clear all application-originated servlet context attributes
if (context != null)
context.clearAttributes();
// Stop resources
resourcesStop();
if ((realm != null) && (realm instanceof Lifecycle)) {
((Lifecycle) realm).stop();
}
if ((cluster != null) && (cluster instanceof Lifecycle)) {
((Lifecycle) cluster).stop();
}
if ((logger != null) && (logger instanceof Lifecycle)) {
((Lifecycle) logger).stop();
}
if ((loader != null) && (loader instanceof Lifecycle)) {
((Lifecycle) loader).stop();
}
} finally {
// Unbinding thread
unbindThread(oldCCL);
}
// Send j2ee.state.stopped notification
if (this.getObjectName() != null) {
Notification notification = new Notification("j2ee.state.stopped",
this.getObjectName(), sequenceNumber++);
broadcaster.sendNotification(notification);
}
// Reset application context
context = null;
// This object will no longer be visible or used.
try {
resetContext();
} catch (Exception ex) {
log.error("Error reseting context " + this + " " + ex, ex);
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
if (log.isDebugEnabled())
log.debug("Stopping complete");
}
destroy()
负责销毁Context任务,在方法中主要是调用基类的destroy()方法销毁Context。
/**
* Destroy needs to clean up the context completely.
*
* The problem is that undoing all the config in start() and restoring a
* 'fresh' state is impossible. After stop()/destroy()/init()/start() we
* should have the same state as if a fresh start was done - i.e read
* modified web.xml, etc. This can only be done by completely removing the
* context object and remapping a new one, or by cleaning up everything.
*
* XXX Should this be done in stop() ?
*
*/
public void destroy() throws Exception {
if (oname != null) {
// Send j2ee.object.deleted notification
Notification notification = new Notification("j2ee.object.deleted",
this.getObjectName(), sequenceNumber++);
broadcaster.sendNotification(notification);
}
super.destroy();
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(DESTROY_EVENT, null);
synchronized (instanceListenersLock) {
instanceListeners = new String[0];
}
}
resetContext()
负责重置Context容器,将恢复至原始状态。
adjustURLPattern(String)
负责将URL规范化。
/**
* Adjust the URL pattern to begin with a leading slash, if appropriate
* (i.e. we are running a servlet 2.2 application). Otherwise, return the
* specified URL pattern unchanged.
*
* @param urlPattern
* The URL pattern to be adjusted (if needed) and returned
*/
protected String adjustURLPattern(String urlPattern) {
if (urlPattern == null)
return (urlPattern);
if (urlPattern.startsWith("/") || urlPattern.startsWith("*."))
return (urlPattern);
if (!isServlet22())
return (urlPattern);
if (log.isDebugEnabled())
log.debug(sm.getString("standardContext.urlPattern.patternWarning",
urlPattern));
return ("/" + urlPattern);
}
bindThread()
绑定线程类加载器,保存现有线程的类加载器,然后将Context的类加载器绑定至当前线程中,将Context资源服务绑定至当前线程,绑定命名服务类加载器,这样可以确保在Context中的资源在同一个类加载器上面。
/**
* 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;
if (getLoader().getClassLoader() != null) {
Thread.currentThread().setContextClassLoader(
getLoader().getClassLoader());
}
DirContextURLStreamHandler.bindThread(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;
}
unbindThread(ClassLoader)
解绑线程类加载器,与bindThrea()方法的功能相反,还原线程类加载器。
/**
* Unbind thread.
*/
private void unbindThread(ClassLoader oldContextClassLoader) {
if (isUseNaming()) {
ContextBindings.unbindThread(this, this);
}
DirContextURLStreamHandler.unbindThread();
Thread.currentThread().setContextClassLoader(oldContextClassLoader);
}
validateURLPattern(String)
验证访问URL是否合法。
/**
* Validate the syntax of a proposed <code><url-pattern></code> for
* conformance with specification requirements.
*
* @param urlPattern
* URL pattern to be validated
*/
private boolean validateURLPattern(String urlPattern) {
if (urlPattern == null)
return (false);
if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) {
return (false);
}
if (urlPattern.startsWith("*.")) {
if (urlPattern.indexOf('/') < 0) {
checkUnusualURLPattern(urlPattern);
return (true);
} else
return (false);
}
if ((urlPattern.startsWith("/")) && (urlPattern.indexOf("*.") < 0)) {
checkUnusualURLPattern(urlPattern);
return (true);
} else
return (false);
}
getServlets()
返回Context中所有的Servlet。
Context作为web app的上下文,负责维护和管理在Context中的组件的生命周期,Session管理,Filter过滤,加载Servlet,接收响应请求,应用所需资源加载和维护,Context的数据共享和数据安全隔离等一个webapp所需要的全部功能,上面讲到的是Context中的部分内容,其他内容还请自己查看。
有不足之处请斧正,欢迎吐槽…
坚持,骚年,你可以的