Chapter 16 explains the shutdown hook that Tomcat uses to always get a chance to do clean-up regardless how the user stops it (i.e. either appropriately by sending a shutdown command or inappropriately by simply closing the console.)
Chapter 15 explains the configuration of a web application through Digester, an exciting open source project from the Apache Software Foundation. For those not initiated, this chapter presents a section that gently introduces the digester library and how to use it to convert the nodes in an XML document to Java objects. It then explains the ContextConfig object that configures a StandardContext instance.
Chapter 14 offers the server and service components. A server provides an elegant start and stop mechanism for the whole servlet container, a service serves as a holder for a container and one or more connectors. The application accompanying this chapter shows how to use a server and a service.
前面的实验中,一个 container 只能和一个 connector 关联,并且启动和停止时通过多条指令完成的,Server + Service 可以帮助你更优雅的管理这些服务。
Server & Implementation
Server 表示的是 Catalina servlet container 以及所属的所有子 component。它提供了一种优雅的方式管理所有服务的开启和停止。
官方定义如下:A Server element represents the entire Catalina servlet container.
/** * Invoke a pre-startup initialization. This is used to allow connectors * to bind to restricted ports under Unix operating environments. */ publicvoidinitialize() throws LifecycleException { if (initialized) thrownew LifecycleException ( sm.getString("standardServer.initialize.initialized")); initialized = true;
// Initialize our defined Services for (int i = 0; i < services.length; i++) { services[i].initialize(); } }
类似的还有 start, stop 方法,处理的逻辑都是类似的,先发送对应的 event,然后 for 循环调用 service 对应的方法
Bootstrap 实现和前面基本一致,最大的区别是在 Engine 声明之后,声明了这节介绍的 Server 和 Service 作为管理 Engine 的容器
1 2 3 4 5
Service service = new StandardService(); service.setName("Stand-alone Service"); Server server = new StandardServer(); server.addService(service); service.addConnector(connector);
Chapter 13 presents the two other containers: host and engine. You can also find the standard implementation of these two containers: org.apache.catalina.core.StandardHost and org.apache.catalina.core.StandardEngine.
/** * Return the Context that would be used to process the specified * host-relative request URI, if any; otherwise return <code>null</code>. * * @param uri Request URI to be mapped */ public Context map(String uri);
Chapter 12 covers the org.apache.catalina.core.StandardContext class that represents a web application. In particular this chapter discusses how a StandardContext object is configured, what happens in it for each incoming HTTP request, how it supports automatic reloading, and how Tomcat 5 shares a thread that executes periodic tasks in its associated components.
/** * Set the Container with which this Logger has been associated. * * @param container The associated Container */ publicvoidsetContainer(Container container){
// Deregister from the old Container (if any) if ((this.container != null) && (this.container instanceof Context)) ((Context) this.container).removePropertyChangeListener(this);
// Process this property change Container oldContainer = this.container; this.container = container; support.firePropertyChange("container", oldContainer, this.container);
// Register with the new Container (if any) if ((this.container != null) && (this.container instanceof Context)) { setReloadable( ((Context) this.container).getReloadable() ); ((Context) this.container).addPropertyChangeListener(this); }
/** * Set the reloadable flag for this Loader. * * @param reloadable The new reloadable flag */ publicvoidsetReloadable(boolean reloadable){
// Process this property change boolean oldReloadable = this.reloadable; this.reloadable = reloadable; support.firePropertyChange("reloadable", new Boolean(oldReloadable), new Boolean(this.reloadable));
// Start or stop our background thread if required if (!started) return; if (!oldReloadable && this.reloadable) threadStart(); elseif (oldReloadable && !this.reloadable) threadStop();
Chapter 11 explains in detail the org.apache.catalina.core.StandardWrapper class that represents a servlet in a web application. In particular, this chapter explains how filters and a servlet’s service method are invoked. The application accompanying this chapter uses StandardWrapper instances to represents servlets.
servlet 可以选择实现 javax.servlet.SingleThreadMode 接口,实现了该接口的 class 称为 SingleThreadModel (STM) servlet。
Servlet 2.4 specification 中关于这个借口的描述如下:
If a servlet implements this interface, you are guaranteed that no two threads will execute concurrently in a servlet’s service method. The servlet container can guarantee this by synchronizing access to a single instance of the servlet, or by maintaining a pool of servlet instances and dispatching each new request to a free servlet. This interface does not prevent synchronization problems that result from servlets accessing shared resources such as static class variables or classes outside the scope of the servlet.
It is true that by implementing SingleThreadModel no two threads will execute a servlet’s service method at the same time. However, to enhance performance the servlet container can create multiple instances of an STM servlet. That means, the STM servlet’s service method can be executed concurrently in different instances. This will introduce synchronization problems if the servlet need to access static class variables or other resources outside the class.
public Servlet allocate()throws ServletException {
if (debug >= 1) log("Allocating an instance");
// If we are currently unloading this servlet, throw an exception if (unloading) thrownew ServletException (sm.getString("standardWrapper.unloading", getName()));
// If not SingleThreadedModel, return the same instance every time if (!singleThreadModel) {
// Return the existing filter instance, if any if (this.filter != null) return (this.filter);
// Identify the class loader we will be using String filterClass = filterDef.getFilterClass(); ClassLoader classLoader = null; if (filterClass.startsWith("org.apache.catalina.")) classLoader = this.getClass().getClassLoader(); else classLoader = context.getLoader().getClassLoader();
// Instantiate a new instance of this filter and return it Class clazz = classLoader.loadClass(filterClass); this.filter = (Filter) clazz.newInstance(); filter.init(this); return (this.filter);
Wrapper wrapper1 = new StandardWrapper(); wrapper1.setName("Primitive"); wrapper1.setServletClass("PrimitiveServlet"); Wrapper wrapper2 = new StandardWrapper(); wrapper2.setName("Modern"); wrapper2.setServletClass("ModernServlet")
Issue
setup 项目之后,访问 URL,抛异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
StandardWrapperValve[Primitive]: Allocate exception for servlet Primitive javax.servlet.ServletException: Error allocating a servlet instance javax.servlet.ServletException: Error allocating a servlet instance at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:654) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:137) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:642) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:479) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:993) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:185) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:642) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:479) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:993) at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2377) at org.apache.catalina.connector.http.HttpProcessor.process(HttpProcessor.java:972) at org.apache.catalina.connector.http.HttpProcessor.run(HttpProcessor.java:1085) at java.lang.Thread.run(Thread.java:748)