前言
上篇文章讲到了Context的启动,在 Context 的 startInternal 方法中调用了子容器的 start 方法,Context 的子容器则是 Wrapper,Wrapper 的实现类是 StandardWrapper。StandardWrapper 没有重载 initInternal 方法。
1. StandardWrapper#startInternal 方法
/**
* Start this component and implement the requirements
* of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
*
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
@Override
protected synchronized void startInternal() throws LifecycleException {
// Send j2ee.state.starting notification
if (this.getObjectName() != null) {
Notification notification = new Notification("j2ee.state.starting",
this.getObjectName(),
sequenceNumber++);
broadcaster.sendNotification(notification);
}
// Start up this component
super.startInternal();
setAvailable(0L);
// Send j2ee.state.running notification
if (this.getObjectName() != null) {
Notification notification =
new Notification("j2ee.state.running", this.getObjectName(),
sequenceNumber++);
broadcaster.sendNotification(notification);
}
}
startInternal 的逻辑也很简单,就是调用父类 ContainerBase 的 startInternal 方法,然后调用 setAvailable(0L) 方法设置 available 属性的值。
/**
* The date and time at which this servlet will become available (in
* milliseconds since the epoch), or zero if the servlet is available.
* If this value equals Long.MAX_VALUE, the unavailability of this
* servlet is considered permanent.
*/
protected long available = 0L;
/**
* Set the available date/time for this servlet, in milliseconds since the
* epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
* that unavailability is permanent and any request for this servlet will return
* an SC_NOT_FOUND error. If this date/time is in the future, any request for
* this servlet will return an SC_SERVICE_UNAVAILABLE error.
*
* @param available The new available date/time
*/
@Override
public void setAvailable(long available) {
long oldAvailable = this.available;
if (available > System.currentTimeMillis())
this.available = available;
else
this.available = 0L;
support.firePropertyChange("available", Long.valueOf(oldAvailable),
Long.valueOf(this.available));
}
从 available 的注释可以看出,它的作用是表示 Servlet 的可用时间的。
2. StandardWrapper#load 方法
在上篇文章中,讲到了Context的startInternal 方法中做了一件事情就是调用 Wrapper 的 load 方法(在 StandardContext#loadOnStartup 中调用的)。在 StandardContext#startInternal 中先调用 Wrapper的 start 方法,然后调用 Wrapper 的 load 方法。
/**
* The (single) possibly uninitialized instance of this servlet.
*/
protected volatile Servlet instance = null;
/**
* Load and initialize an instance of this servlet, if there is not already
* at least one initialized instance. This can be used, for example, to
* load servlets that are marked in the deployment descriptor to be loaded
* at server startup time.
* <p>
* <b>IMPLEMENTATION NOTE</b>: Servlets whose classnames begin with
* <code>org.apache.catalina.</code> (so-called "container" servlets)
* are loaded by the same classloader that loaded this class, rather than
* the classloader for the current web application.
* This gives such classes access to Catalina internals, which are
* prevented for classes loaded for web applications.
*
* @exception ServletException if the servlet init() method threw
* an exception
* @exception ServletException if some other loading problem occurs
*/
@Override
public synchronized void load() throws ServletException {
instance = loadServlet();
if (!instanceInitialized) {
initServlet(instance);
}
if (isJspServlet) {
StringBuilder oname = new StringBuilder(getDomain());
oname.append(":type=JspMonitor");
oname.append(getWebModuleKeyProperties());
oname.append(",name=");
oname.append(getName());
oname.append(getJ2EEKeyProperties());
try {
jspMonitorON = new ObjectName(oname.toString());
Registry.getRegistry(null, null)
.registerComponent(instance, jspMonitorON, null);
} catch (Exception ex) {
log.info(sm.getString("standardWrapper.jspMonitorError", instance));
}
}
}
load 方法逻辑很简单,先调用 loadServlet() 获取一个 Servlet 对象,就是通过 servletClass 属性指定的类名,调用 InstanceManager#newInstance(servletClass) 方法来创建一个 Servlet 对象。
然后调用 initServlet(instance) 来初始化这个 Servlet 对象,也就是调用这个 Servlet 对象的 init 方法。
可以看出 Wrapper 里有一个 Servlet 属性,Wrapper 正是对 Servlet 的包装。
3. StandardWrapper#backgroundProcess 方法
/**
* Execute a periodic task, such as reloading, etc. This method will be
* invoked inside the classloading context of this container. Unexpected
* throwables will be caught and logged.
*/
@Override
public void backgroundProcess() {
super.backgroundProcess();
if (!getState().isAvailable())
return;
if (getServlet() instanceof PeriodicEventListener) {
((PeriodicEventListener) getServlet()).periodicEvent();
}
}
backgroundProcess 方法很简单,只是调用一下父类 ContainerBase 的 backgroundProcess 方法。
小结
本文分析了 Wrapper 容器的启动,wrapper 在 tomcat 启动过程中的关键点就是初始化了 Servlet。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。