`
Donald_Draper
  • 浏览: 953443 次
社区版块
存档分类
最新评论

Tomcat的Host初始化(Context,Listener,Filter,Servlet)

阅读更多
Tomcat的Engine初始化,启动过程:http://donald-draper.iteye.com/blog/2327119
Tomcat配置文件:
<Engine name="Catalina" defaultHost="localhost">
      <!--
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
      -->
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
 </Engine>

Host作为Engine的子容器,我们来看看Host的初始化与启动
public class StandardHost extends ContainerBase implements Host {
  private final Object aliasesLock = new Object();
    
    /**The application root for this Host.默认应用根目录*/
    private String appBase = "webapps";
    /** The XML root for this Host.*/
    private String xmlBase = null;
    /** The auto deploy flag for this Host.*/
    private boolean autoDeploy = true;
    /**
     * The Java class name of the default context configuration class
     * for deployed web applications.
     */
    //上下文配置类
    private String configClass =
        "org.apache.catalina.startup.ContextConfig";
    /**
     * The Java class name of the default Context implementation class for
     * deployed web applications.
     */
    //Host的上下文加载实现类
    private String contextClass =
        "org.apache.catalina.core.StandardContext";
    /** The deploy on startup flag for this Host.*/
    private boolean deployOnStartup = true;
    /** deploy Context XML config files property. */
    private boolean deployXML = !Globals.IS_SECURITY_ENABLED;
    /**
     * Should XML files be copied to
     * $CATALINA_BASE/conf/&lt;engine&gt;/&lt;host&gt; by default when
     * a web application is deployed?
     */
    private boolean copyXML = false;
    /**
     * The Java class name of the default error reporter implementation class
     * for deployed web applications.
     */
    private String errorReportValveClass =
        "org.apache.catalina.valves.ErrorReportValve";
    //实现类类信息
    private static final String info =
        "org.apache.catalina.core.StandardHost/1.0";
    //是否解压WARs
    private boolean unpackWARs = true;
    //applications的工作目录
    private String workDir = null;
     //启动 appBase and xmlBase的时候,是否创建目录
     private boolean createDirs = true;
     //子ClassLoaderMap,以便检测内存泄漏情况
     private Map<ClassLoader, String> childClassLoaders =
         new WeakHashMap<ClassLoader, String>();
    private Pattern deployIgnore = null;
    private boolean undeployOldVersions = false;
    private boolean failCtxIfServletStartFails = false;
    //构造HOST
     public StandardHost() {
        super();
        pipeline.setBasic(new StandardHostValve());
    }
    //启动
    protected synchronized void startInternal() throws LifecycleException {
        String errorValve = getErrorReportValveClass();
        if ((errorValve != null) && (!errorValve.equals(""))) {
            try {
                boolean found = false;
                Valve[] valves = getPipeline().getValves();
                for (Valve valve : valves) {
                    if (errorValve.equals(valve.getClass().getName())) {
                        found = true;
                        break;
                    }
                }
                if(!found) {
                    Valve valve =
                        (Valve) Class.forName(errorValve).newInstance();
	            //添加valve到Pipeline
                    getPipeline().addValve(valve);
                }
            } 
        }
	//这个调用的是ContainerBase的startInternal
	//这个在上面我们已经说过
        super.startInternal();
	}
}

//StandardHostValve
final class StandardHostValve extends ValveBase {
    static final boolean STRICT_SERVLET_COMPLIANCE;
    static final boolean ACCESS_SESSION;
    static {
        STRICT_SERVLET_COMPLIANCE = Globals.STRICT_SERVLET_COMPLIANCE;
        String accessSession = System.getProperty(
                "org.apache.catalina.core.StandardHostValve.ACCESS_SESSION");
        if (accessSession == null) {
            ACCESS_SESSION = STRICT_SERVLET_COMPLIANCE;
        } else {
            ACCESS_SESSION = Boolean.parseBoolean(accessSession);
        }
    }
    //根据request的URI选择一个child context来处理Request,
    //如果没有匹配的上下文,则返回HTTP error
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
        //获取请求的上下文
        Context context = request.getContext();
        if (context == null) {
            response.sendError
                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                 sm.getString("standardHost.noContext"));
            return;
        }
        // Bind the context CL to the current thread
        if( context.getLoader() != null ) {
            // Not started - it should check for availability first
            // This should eventually move to Engine, it's generic.
            if (Globals.IS_SECURITY_ENABLED) {
                PrivilegedAction<!-- <Void> --> pa = new PrivilegedSetTccl(
                        context.getLoader().getClassLoader());
                AccessController.doPrivileged(pa);                
            } else {
                Thread.currentThread().setContextClassLoader
                        (context.getLoader().getClassLoader());
            }
        }
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(context.getPipeline().isAsyncSupported());
        }
        boolean asyncAtStart = request.isAsync(); 
        boolean asyncDispatching = request.isAsyncDispatching();
        if (asyncAtStart || context.fireRequestInitEvent(request)) {
            Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
            // Look for (and render if found) an application level error page
            if (response.isErrorReportRequired()) {
                if (t != null) {
                    throwable(request, response, t);
                } else {
		    //返回处理状态
                    status(request, response);
                }
            }
        }
    }
    //返回处理状态,如果异常发生,返回错误状态码,对应的错误页面(web.xml-errorPage)
    private void status(Request request, Response response) {
     int statusCode = response.getStatus();

        // Handle a custom error page for this status code
        Context context = request.getContext();
        if (context == null)
            return;

        /* Only look for error pages when isError() is set.
         * isError() is set when response.sendError() is invoked. This
         * allows custom error pages without relying on default from
         * web.xml.
         */
        if (!response.isError())
            return;
         //从Context中,获取statusCode对应的页面
        ErrorPage errorPage = context.findErrorPage(statusCode);
        if (errorPage == null) {
            // Look for a default error page
            errorPage = context.findErrorPage(0);
        }
        if (errorPage != null && response.isErrorReportRequired()) {
            response.setAppCommitted(false);
            request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
                              Integer.valueOf(statusCode));
            String message = response.getMessage();
            if (message == null)
                message = "";
            request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
            request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
                    errorPage.getLocation());
            request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,
                    DispatcherType.ERROR);
            Wrapper wrapper = request.getWrapper();
            if (wrapper != null)
                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,
                                  wrapper.getName());
            request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,
                                 request.getRequestURI());
            if (custom(request, response, errorPage)) {
                response.setErrorReported();
                try {
                    response.finishResponse();
                } catch (ClientAbortException e) {
                    // Ignore
                } catch (IOException e) {
                    container.getLogger().warn("Exception Processing " + errorPage, e);
                }
            }
        }
}

//ErrorPage
public class ErrorPage implements Serializable {
    //错误码
    private int errorCode = 0;
    private String exceptionType = null;
    //处理异常的Handler位置(context)
    private String location = null;
}

在StandardHost中我们看到有一个StandardContext,
StandardContext也继承了ContainerBase
public class StandardContext extends ContainerBase
        implements Context, NotificationEmitter {
   public StandardContext() {
        super();
        pipeline.setBasic(new StandardContextValve());
        broadcaster = new NotificationBroadcasterSupport();
        // Set defaults
        if (!Globals.STRICT_SERVLET_COMPLIANCE) {
            // Strict servlet compliance requires all extension mapped servlets
            // to be checked against welcome files
            resourceOnlyServlets.add("jsp");
        }
    //url安全字符集
    protected static URLEncoder urlEncoder;
    static {
        urlEncoder = new URLEncoder();
        urlEncoder.addSafeCharacter('~');
        urlEncoder.addSafeCharacter('-');
        urlEncoder.addSafeCharacter('_');
        urlEncoder.addSafeCharacter('.');
        urlEncoder.addSafeCharacter('*');
        urlEncoder.addSafeCharacter('/');
    }
    /**
     * The set of application listener class names configured for this
     * application, in the order they were encountered in the resulting merged
     * web.xml file.
     */
    private ApplicationListener applicationListeners[] =new ApplicationListener[0];
    private final Object applicationListenersLock = new Object();
    /** The ordered set of ServletContainerInitializers for this web application.*/
    private Map<ServletContainerInitializer,Set<Class<?>>> initializers =
        new LinkedHashMap<ServletContainerInitializer,Set<Class<?>>>(); 
    /**The set of application parameters defined for this application.*/
    private ApplicationParameter applicationParameters[] =
        new ApplicationParameter[0];
    private final Object applicationParametersLock = new Object();
    /** The Locale to character set mapper for this application.*/
    private CharsetMapper charsetMapper = null;
    /** The Java class name of the CharsetMapper class to be created.*/
    private String charsetMapperClass ="org.apache.catalina.util.CharsetMapper";
    /** The URL of the XML descriptor for this context.*/
    private URL configFile = null;
    /** The "correctly configured" flag for this Context.*/
    private boolean configured = false;
    /** The security constraints for this web application.*/
    private volatile SecurityConstraint constraints[] = new SecurityConstraint[0];
    private final Object constraintsLock = new Object();
    /** The ServletContext implementation associated with this Context.*/
    protected ApplicationContext context = null;
    /**
     * The wrapped version of the associated ServletContext that is presented
     * to listeners that are required to have limited access to ServletContext
     * methods. See Servlet 3.0 section 4.4.
     */
    private NoPluggabilityServletContext noPluggabilityServletContext = null;
    /**Compiler classpath to use.*/
    private String compilerClasspath = null;
    /**Should we attempt to use cookies for session id communication?*/
    private boolean cookies = true;
    /**
     * Should we allow the <code>ServletContext.getContext()</code> method
     * to access the context of other web applications in this server?
     */
    private boolean crossContext = false;
    /**Encoded path.*/
    private String encodedPath = null;
    /**Unencoded path for this web application.*/
    private String path = null;
    /**
     * The "follow standard delegation model" flag that will be used to
     * configure our ClassLoader.
     */
    private boolean delegate = false;
    /** The display name of this web application.*/
    private String displayName = null;
    /**  Override the default context xml location.*/
    private String defaultContextXml;
    /**  Override the default web xml location.*/
    private String defaultWebXml;
    /** The distributable flag for this web application.*/
    private boolean distributable = false;
    /** The document root for this web application.*/
    private String docBase = null;
    //异常页面定义映射
    private HashMap<String, ErrorPage> exceptionPages =
        new HashMap<String, ErrorPage>();
    /**
     * The set of filter configurations (and associated filter instances) we
     * have initialized, keyed by filter name.
     */
    private HashMap<String, ApplicationFilterConfig> filterConfigs =
        new HashMap<String, ApplicationFilterConfig>();
   //filter定义
    private HashMap<String, FilterDef> filterDefs =
        new HashMap<String, FilterDef>();
    //Filter映射    
    private final ContextFilterMaps filterMaps = new ContextFilterMaps();
    /**
     * The set of classnames of InstanceListeners that will be added
     * to each newly created Wrapper by <code>createWrapper()</code>.
     */
    private String instanceListeners[] = new String[0];
    private final Object instanceListenersLock = new Object();
    /** The login configuration descriptor for this web application. */
    private LoginConfig loginConfig = null;
    /** The mapper associated with this context.*/
    private org.apache.tomcat.util.http.mapper.Mapper mapper = 
        new org.apache.tomcat.util.http.mapper.Mapper();
    /** The naming context listener for this web application.*/
    private NamingContextListener namingContextListener = null;
    /** The naming resources for this web application. */
    private NamingResources namingResources = null;
    /** The message destinations for this web application.*/
    private HashMap<String, MessageDestination> messageDestinations =
        new HashMap<String, MessageDestination>();
    /** The MIME mappings for this web application, keyed by extension.*/
    private HashMap<String, String> mimeMappings =new HashMap<String, String>();
     /** Special case: error page for status 200. */
     private ErrorPage okErrorPage = null;
    /**
     * The context initialization parameters for this web application,keyed by name.
     */
    private final ConcurrentMap<String, String> parameters = new ConcurrentHashMap<String, String>();
    /** Context level override for default {@link StandardHost#isCopyXML()}.*/
    private boolean copyXML = false;
     /** The default context override flag for this web application.*/
    private boolean override = false;
    /** The original document root for this web application.*/
    private String originalDocBase = null;
    //角色映射
    private HashMap<String, String> roleMappings =new HashMap<String, String>();
    //安全角色
    private String securityRoles[] = new String[0];
    private final Object securityRolesLock = new Object();
    //SevletMapping
    private HashMap<String, String> servletMappings = new HashMap<String, String>();
    private final Object servletMappingsLock = new Object();
    /** The session timeout (in minutes) for this web application.*/
    private int sessionTimeout = 30;
    /** The notification sequence number.*/
    private AtomicLong sequenceNumber = new AtomicLong(0);
    private HashMap<Integer, ErrorPage> statusPages =new HashMap<Integer, ErrorPage>();
    //应用欢迎文件
    private String welcomeFiles[] = new String[0];
    private final Object welcomeFilesLock = new Object();
    /** The pathname to the work directory for this context (relative to the server's home if not absolute). */
    //工作目录
    private String workDir = null;
    //Wrapper的实现类Java class name
    private String wrapperClassName = StandardWrapper.class.getName();
    private Class<?> wrapperClass = null;
    /**Caching allowed flag.*/
    private boolean cachingAllowed = true;
    /** Cache TTL in ms.*/
    protected int cacheTTL = 5000;
    private String sessionCookieName;    
    private String sessionCookiePath;
    //ApplicationContext#createServlet(Class),Servlet集合
    private Set<Servlet> createdServlets = new HashSet<Servlet>();
    //初始化
    protected void initInternal() throws LifecycleException {
		super.initInternal();
		if (processTlds) {
		   //添加tld监听器
		    this.addLifecycleListener(new TldConfig());
		}
		// Register the naming resources
		if (namingResources != null) {
		    namingResources.init();
		}
		// Send j2ee.object.created notification 
		if (this.getObjectName() != null) {
		    Notification notification = new Notification("j2ee.object.created",
			    this.getObjectName(), sequenceNumber.getAndIncrement());
		    broadcaster.sendNotification(notification);
		}
	 }
   protected synchronized void startInternal() throws LifecycleException {
        if(log.isDebugEnabled()) log.debug("Starting " + getBaseName());
        // Send j2ee.state.starting notification 
        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();//配置namingResources
        }
        // 初始化Cached,CacheTTL,CacheMaxSize,CacheObjectMaxSize等
        if (webappResources == null) {   // (1) Required by Loader
            try {
                String docBase = getDocBase();
                if (docBase == null) {
                    setResources(new EmptyDirContext());
                } else if (docBase.endsWith(".war")
                        && !(new File(getBasePath())).isDirectory()) {
                    setResources(new WARDirContext());
                } else {
                    setResources(new FileDirContext());
                }
            } 
        }
        if (ok) {
            if (!resourcesStart()) {
                throw new LifecycleException("Error in resourceStart()");
            }
        }
        //配置WebappLoader
        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);
        } 
        // 绑定线程ClassLoader
        ClassLoader oldCCL = bindThread();
        try {
            if (ok) {
                // 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 ((cluster != null) && (cluster instanceof Lifecycle))
                    ((Lifecycle) cluster).start();
                Realm realm = getRealmInternal();
                if ((realm != null) && (realm instanceof Lifecycle))
                    ((Lifecycle) realm).start();
                if ((resources != null) && (resources instanceof Lifecycle))
                    ((Lifecycle) resources).start();
                // Notify our interested LifecycleListeners
                fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
                // Start our child containers, if not already started
                for (Container child : findChildren()) {
                    if (!child.getState().isAvailable()) {
                        child.start();
                    }
                }
                // Start the Valves in our pipeline (including the basic),
                // if any
                if (pipeline instanceof Lifecycle) {
                    ((Lifecycle) pipeline).start();
                }
                // Acquire clustered manager
                Manager contextManager = null;
                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();
                    }
                } 
                // Configure default manager if none was specified
                if (contextManager != null) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("standardContext.manager",
                                contextManager.getClass().getName()));
                    }
                    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);
                }
            }

        } finally {
            // Unbinding thread
            unbindThread(oldCCL);
        }
        if (!getConfigured()) {
            log.error(sm.getString("standardContext.configurationFail"));
            ok = false;
        }
        // We put the resources into the servlet context
        if (ok)
            getServletContext().setAttribute
                (Globals.RESOURCES_ATTR, getResources());
	//初始化欢迎页面
        mapper.setContext(getPath(), welcomeFiles, resources);
        // Binding thread
        oldCCL = bindThread();

        if (ok ) {
            if (getInstanceManager() == null) {
                javax.naming.Context context = null;
                if (isUseNaming() && getNamingContextListener() != null) {
                    context = getNamingContextListener().getEnvContext();
                }
                Map<String, Map<String, String>> injectionMap = buildInjectionMap(
                        getIgnoreAnnotations() ? new NamingResources(): getNamingResources());
                setInstanceManager(new DefaultInstanceManager(context,
                        injectionMap, this, this.getClass().getClassLoader()));
                getServletContext().setAttribute(
                        InstanceManager.class.getName(), getInstanceManager());
            }
        }

        try {
            // Create context attributes that will be required
            if (ok) {
                getServletContext().setAttribute(
                        JarScanner.class.getName(), getJarScanner());
            }
            //初始化上下文参数
            mergeParameters();
            // Call ServletContainerInitializers
            for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
                initializers.entrySet()) {
                try {
                    entry.getKey().onStartup(entry.getValue(),
                            getServletContext());
            }
            // Configure and call application event listeners
            if (ok) {
	       //初始化应用监听器
                if (!listenerStart()) {
                    log.error(sm.getString("standardContext.listenerFail"));
                    ok = false;
                }
            }
            try {
                // Start manager
                if ((manager != null) && (manager instanceof Lifecycle)) {
                    ((Lifecycle) getManager()).start();
                }
            } 
            // Configure and call application filters
            if (ok) {
                //初始化Fliter
                if (!filterStart()) {
                    log.error(sm.getString("standardContext.filterFail"));
                    ok = false;
                }
            }    
            // Load and initialize all "load on startup" servlets
            if (ok) {
	        //初始化servlet关键步骤,StandardWrapper为Sevlet的包装类
                if (!loadOnStartup(findChildren())){
                    log.error(sm.getString("standardContext.servletFail"));
                    ok = false;
                }
            }            
            // Start ContainerBackgroundProcessor thread
            super.threadStart();
        } finally {
            // Unbinding thread
            unbindThread(oldCCL);
        }
        startTime=System.currentTimeMillis();
        // Send j2ee.state.running notification 
        if (ok && (this.getObjectName() != null)) {
            Notification notification = 
                new Notification("j2ee.state.running", this.getObjectName(),
                                 sequenceNumber.getAndIncrement());
            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) {
            setState(LifecycleState.FAILED);
        } else {
            setState(LifecycleState.STARTING);
        }
    }
    //初始化Fliter
    public boolean filterStart() {
        // Instantiate and record a FilterConfig for each defined filter
        boolean ok = true;
        synchronized (filterConfigs) {
            filterConfigs.clear();
            for (Entry<String, FilterDef> entry : filterDefs.entrySet()) {
                String name = entry.getKey();
                if (getLogger().isDebugEnabled())
                    getLogger().debug(" Starting filter '" + name + "'");
                ApplicationFilterConfig filterConfig = null;
                try {
                    filterConfig =
                        new ApplicationFilterConfig(this, entry.getValue());
                    filterConfigs.put(name, filterConfig);
                }
            }
        }
        return (ok);
    }
     //加载StandardWrapper,即Servlet包装类
     public boolean loadOnStartup(Container children[]) {
        // Collect "load on startup" servlets that need to be initialized
        TreeMap<Integer, ArrayList<Wrapper>> map =
            new TreeMap<Integer, ArrayList<Wrapper>>();
        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<Wrapper> list = map.get(key);
            if (list == null) {
                list = new ArrayList<Wrapper>();
                map.put(key, list);
            }
            list.add(wrapper);
        }
        // Load the collected "load on startup" servlets
        for (ArrayList<Wrapper> list : map.values()) {
            for (Wrapper wrapper : list) {
                try {
		    //关键在这个load中
                    wrapper.load();
                } 
            }
        }
        return true;
    }
}

从上面可以分析得出StardardContext主要,是根据Web.xml的配置,
初始化欢迎界面,角色权限,初始参数,错误处理,Listener,Filter
和Sevlet等。
来看StandardWrapper从load函数,StandardWrapper同样继承里ContainerBase
,作为一个容器
public class StandardWrapper extends ContainerBase
    implements ServletConfig, Wrapper, NotificationEmitter {
     protected static final String[] DEFAULT_SERVLET_METHODS = new String[] {
                                                    "GET", "HEAD", "POST" };
    //为StandardWrapper创建一个默认的StandardWrapperValve
    public StandardWrapper() {

        super();
        swValve=new StandardWrapperValve();
        pipeline.setBasic(swValve);
        broadcaster = new NotificationBroadcasterSupport();
    }
    **
     * The count of allocations that are currently active (even if they
     * are for the same instance, as will be true on a non-STM servlet).
     */
    protected AtomicInteger countAllocated = new AtomicInteger(0);
    /**
     * The load-on-startup order value (negative value means load on
     * first call) for this servlet.
     */
    protected int loadOnStartup = -1;
    protected volatile Servlet instance = null;
    /**
     * Mappings associated with the wrapper.
     */
    protected ArrayList<String> mappings = new ArrayList<String>();
    /**
     * The initialization parameters for this servlet, keyed by
     * parameter name.
     */
    protected HashMap<String, String> parameters = new HashMap<String, String>();
    /**
     * True if this StandardWrapper is for the JspServlet
     */
    protected boolean isJspServlet;
    /**
     * The ObjectName of the JSP monitoring mbean
     */
    protected ObjectName jspMonitorON;
    //Servlet栈
    protected Stack<Servlet> instancePool = null;
    //启动Wrapper容器
    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);
        }
    }
     //创建一个Servlet实例
    public synchronized void load() throws ServletException {
         //加载Servlet实例
        instance = loadServlet();
        if (!instanceInitialized) {
	    //初始化Servlet
            initServlet(instance);
        }
	//JSP页面Servlet的处理
        if (isJspServlet) {
            StringBuilder oname =
                new StringBuilder(MBeanUtils.getDomain(getParent()));
            
            oname.append(":type=JspMonitor,name=");
            oname.append(getName());
            oname.append(getWebModuleKeyProperties());
            try {
                jspMonitorON = new ObjectName(oname.toString());
                Registry.getRegistry(null, null)
                    .registerComponent(instance, jspMonitorON, null);
            } 
        }
    }
    //加载Servlet
      public synchronized Servlet loadServlet() throws ServletException {

        // Nothing to do if we already have an instance or an instance pool
        if (!singleThreadModel && (instance != null))
            return instance;
        PrintStream out = System.out;
        if (swallowOutput) {
            SystemLogHandler.startCapture();
        }
        Servlet servlet;
        try {
            long t1=System.currentTimeMillis();
            // Complain if no servlet class has been specified
            if (servletClass == null) {
                unavailable(null);
                throw new ServletException
                    (sm.getString("standardWrapper.notClass", getName()));
            }
            InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager();
            try {
	        //加载servletClass实例
                servlet = (Servlet) instanceManager.newInstance(servletClass);
            } 
            if (multipartConfigElement == null) {
                MultipartConfig annotation =
                        servlet.getClass().getAnnotation(MultipartConfig.class);
                if (annotation != null) {
                    multipartConfigElement =
                            new MultipartConfigElement(annotation);
                }
            }
            processServletSecurityAnnotation(servlet.getClass());
            // Special handling for ContainerServlet instances
            if ((servlet instanceof ContainerServlet) &&
                    (isContainerProvidedServlet(servletClass) ||
                            ((Context) getParent()).getPrivileged() )) {
                ((ContainerServlet) servlet).setWrapper(this);
            }
            classLoadTime=(int) (System.currentTimeMillis() -t1);
            if (servlet instanceof SingleThreadModel) {
                if (instancePool == null) {
		    //初始化Servlet栈
                    instancePool = new Stack<Servlet>();
                }
                singleThreadModel = true;
            }
            initServlet(servlet);
            fireContainerEvent("load", this);
            loadTime=System.currentTimeMillis() -t1;
        } finally {
            if (swallowOutput) {
                String log = SystemLogHandler.stopCapture();
                if (log != null && log.length() > 0) {
                    if (getServletContext() != null) {
                        getServletContext().log(log);
                    } else {
                        out.println(log);
                    }
                }
            }
        }
        return servlet;
    }
     //初始化Servlet
     private synchronized void initServlet(Servlet servlet)
            throws ServletException {
        if (instanceInitialized && !singleThreadModel) return;
        // Call the initialization method of this servlet
        try {
            instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,servlet);
            if( Globals.IS_SECURITY_ENABLED) {
                boolean success = false;
                try {
                    Object[] args = new Object[] { facade };
		    //检查权限
                    SecurityUtil.doAsPrivilege("init",
                                               servlet,
                                               classType,
                                               args);
                    success = true;
                } finally {
                    if (!success) {
                        // destroy() will not be called, thus clear the reference now
                        SecurityUtil.remove(servlet);
                    }
                }
            } else {
	       [color=red] //初始化Servlet,这个方法大家应该熟悉
                servlet.init(facade);[/color]
            }
            instanceInitialized = true;
            instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
                                              servlet);
        } 
    }
}

//StandardWrapperValve,Servlet请求处理包装类
final class StandardWrapperValve
    extends ValveBase {
    //------------------------------------------------------ Constructor
    public StandardWrapperValve() {
        super(true);
    }
    // ----------------------------------------------------- Instance Variables

    // Some JMX statistics. This valve is associated with a StandardWrapper.
    // We expose the StandardWrapper as JMX ( j2eeType=Servlet ). The fields
    // are here for performance.
    private volatile long processingTime;
    private volatile long maxTime;
    private volatile long minTime = Long.MAX_VALUE;
    private volatile int requestCount;
    private volatile int errorCount;
    //处理Http请求,根据Servlet的映射
     public final void invoke(Request request, Response response)
        throws IOException, ServletException {
        // Initialize local variables we may need
        boolean unavailable = false;
        Throwable throwable = null;
        // This should be a Request attribute...
        long t1=System.currentTimeMillis();
        requestCount++;
        StandardWrapper wrapper = (StandardWrapper) getContainer();
        Servlet servlet = null;
	//从StandardWrapper中获取Context
        Context context = (Context) wrapper.getParent();
        
        // 检查Context状态是否可利用,否返回错误
        if (!context.getState().isAvailable()) {
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                           sm.getString("standardContext.isUnavailable"));
            unavailable = true;
        }

        // Check for the servlet being marked unavailable
        if (!unavailable && wrapper.isUnavailable()) {
            container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
                    wrapper.getName()));
            long available = wrapper.getAvailable();
            if ((available > 0L) && (available < Long.MAX_VALUE)) {
	        //设置头部
                response.setDateHeader("Retry-After", available);
                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                        sm.getString("standardWrapper.isUnavailable",
                                wrapper.getName()));
            } else if (available == Long.MAX_VALUE) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND,
                        sm.getString("standardWrapper.notFound",
                                wrapper.getName()));
            }
            unavailable = true;
        }
        // Allocate a servlet instance to process this request
        try {
            if (!unavailable) {
	       //从StandardWraper中获取Servlet实例,下面我们分析这个函数
                servlet = wrapper.allocate();
            }
        } 
        // Identify if the request is Comet related now that the servlet has been allocated
        boolean comet = false;
        if (servlet instanceof CometProcessor && Boolean.TRUE.equals(request.getAttribute(
                Globals.COMET_SUPPORTED_ATTR))) {
            comet = true;
            request.setComet(true);
        }
        
        MessageBytes requestPathMB = request.getRequestPathMB();
        DispatcherType dispatcherType = DispatcherType.REQUEST;
        if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC; 
        request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
        request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
                requestPathMB);
        // Create the filter chain for this request
        ApplicationFilterFactory factory =
            ApplicationFilterFactory.getInstance();
	//创建应用Filter链
        ApplicationFilterChain filterChain =
            factory.createFilterChain(request, wrapper, servlet);
        
        // Reset comet flag value after creating the filter chain
        request.setComet(false);

        // Call the filter chain for this request
        // NOTE: This also calls the servlet's service() method
        try {
            if ((servlet != null) && (filterChain != null)) {
                // Swallow output if needed
                if (context.getSwallowOutput()) {
                    try {
                        SystemLogHandler.startCapture();
                        if (request.isAsyncDispatching()) {
                            request.getAsyncContextInternal().doInternalDispatch();
                        } else if (comet) {
                            filterChain.doFilterEvent(request.getEvent());
                            request.setComet(true);
                        } else {
			    //Filter处理
                            filterChain.doFilter(request.getRequest(), 
                                    response.getResponse());
                        }
                    } finally {
                        String log = SystemLogHandler.stopCapture();
                        if (log != null && log.length() > 0) {
                            context.getLogger().info(log);
                        }
                    }
                } else {
                    if (request.isAsyncDispatching()) {
                        request.getAsyncContextInternal().doInternalDispatch();
                    } else if (comet) {
                        request.setComet(true);
                        filterChain.doFilterEvent(request.getEvent());
                    } else {
                        filterChain.doFilter
                            (request.getRequest(), response.getResponse());
                    }
                }

            }
        } 
        // Release the filter chain (if any) for this request
        if (filterChain != null) {
            if (request.isComet()) {
                // If this is a Comet request, then the same chain will be used for the
                // processing of all subsequent events.
                filterChain.reuse();
            } else {
                filterChain.release();
            }
        }

        // Deallocate the allocated servlet instance
        try {
            if (servlet != null) {
                wrapper.deallocate(servlet);
            }
        } catch (Throwable e) {
            ExceptionUtils.handleThrowable(e);
            container.getLogger().error(sm.getString("standardWrapper.deallocateException",
                             wrapper.getName()), e);
            if (throwable == null) {
                throwable = e;
                exception(request, response, e);
            }
        }

        // If this servlet has been marked permanently unavailable,
        // unload it and release this instance
        try {
            if ((servlet != null) &&
                (wrapper.getAvailable() == Long.MAX_VALUE)) {
                wrapper.unload();
            }
        } catch (Throwable e) {
            ExceptionUtils.handleThrowable(e);
            container.getLogger().error(sm.getString("standardWrapper.unloadException",
                             wrapper.getName()), e);
            if (throwable == null) {
                throwable = e;
                exception(request, response, e);
            }
        }
        long t2=System.currentTimeMillis();

        long time=t2-t1;
        processingTime += time;
        if( time > maxTime) maxTime=time;
        if( time < minTime) minTime=time;

    }
}

//从StandardWrapperValve可以看出,其通过包装Request,StandardWrapper,Servlet
到ApplicationFilterChain,然后执行Filter的doFilter方法;
下面我们看一ApplicationFilterChain
final class ApplicationFilterChain implements FilterChain, CometFilterChain {

    // Used to enforce requirements of SRV.8.2 / SRV.14.2.5.1
    //ThreadLocal,线程本地变量,隔离多线程下,每个线程ServletRequest,ServletResponse
    //这种思想值得借鉴
    private static final ThreadLocal<ServletRequest> lastServicedRequest;
    private static final ThreadLocal<ServletResponse> lastServicedResponse;

    static {
        if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
            lastServicedRequest = new ThreadLocal<ServletRequest>();
            lastServicedResponse = new ThreadLocal<ServletResponse>();
        } else {
            lastServicedRequest = null;
            lastServicedResponse = null;
        }
    }
   /**
     * The servlet instance to be executed by this chain.
     */
    private Servlet servlet = null;
    /**
     * Static class array used when the SecurityManager is turned on and 
     * <code>doFilter</code> is invoked.
     */
    private static Class<?>[] classType = new Class[]{ServletRequest.class, 
                                                      ServletResponse.class,
                                                      FilterChain.class};
                                                   
    /**
     * Static class array used when the SecurityManager is turned on and 
     * <code>service</code> is invoked.
     */                                                 
    private static Class<?>[] classTypeUsedInService = new Class[]{
                                                         ServletRequest.class,
                                                         ServletResponse.class};
  //过滤Servlet
  public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {
        if( Globals.IS_SECURITY_ENABLED ) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            try {
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedExceptionAction<Void>() {
                        @Override
                        public Void run() 
                            throws ServletException, IOException {
                            internalDoFilter(req,res);
                            return null;
                        }
                    }
                );
            }
    }
    //内部过滤处理
    private void internalDoFilter(ServletRequest request, 
                                  ServletResponse response)
        throws IOException, ServletException {

        // Call the next filter if there is one
        if (pos < n) {
            ApplicationFilterConfig filterConfig = filters[pos++];
            Filter filter = null;
            try {
                filter = filterConfig.getFilter();
                support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
                                          filter, request, response);
                
                if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                        filterConfig.getFilterDef().getAsyncSupported())) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                            Boolean.FALSE);
                }
                if( Globals.IS_SECURITY_ENABLED ) {
		    //检查权限,获取权限
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal = 
                        ((HttpServletRequest) req).getUserPrincipal();

                    Object[] args = new Object[]{req, res, this};
                    SecurityUtil.doAsPrivilege
                        ("doFilter", filter, classType, args, principal);
                    
                } else {  
		    //调用Filter的doFilter函数
                    filter.doFilter(request, response, this);
                }
                support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
                                          filter, request, response);
            } 
        }

        // We fell off the end of the chain -- call the servlet instance
        try {
            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                lastServicedRequest.set(request);
                lastServicedResponse.set(response);
            }

            support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,
                                      servlet, request, response);
            if (request.isAsyncSupported()
                    && !support.getWrapper().isAsyncSupported()) {
                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                        Boolean.FALSE);
            }
            // Use potentially wrapped request from this point
            if ((request instanceof HttpServletRequest) &&
                (response instanceof HttpServletResponse)) {
                    
                if( Globals.IS_SECURITY_ENABLED ) {
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal = 
                        ((HttpServletRequest) req).getUserPrincipal();
                    Object[] args = new Object[]{req, res};
		    //如果有权限限制,这检查权限,执行Service()
                    SecurityUtil.doAsPrivilege("service",
                                               servlet,
                                               classTypeUsedInService, 
                                               args,
                                               principal);   
                } else {  
		     [color=red]//这个方法熟悉了吧,调用Servlet的service函数
                    servlet.service(request, response);[/color]
                }
            } else {
                servlet.service(request, response);
            }
            support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
                                      servlet, request, response);
        } 
        } finally {
            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
	        //清除线程的本地变量ServletRequest,ServletResponse
                lastServicedRequest.set(null);
                lastServicedResponse.set(null);
            }
        }
    }
}

上面我们分析 StandardWraper时,他的invove()函数获取Servlet有一个方法
allocate,这个方法的实现在StandardWrape
//从StandardWraper中获取Servlet实例,下面我们分析这个函数
                servlet = wrapper.allocate();
public class StandardWrapper extends ContainerBase
    implements ServletConfig, Wrapper, NotificationEmitter {
     /**
     * Stack containing the STM instances.
     */
     //servlet实例栈池
    protected Stack<Servlet> instancePool = null;
    /**
     * The count of allocations that are currently active (even if they
     * are for the same instance, as will be true on a non-STM servlet).
     */
    protected AtomicInteger countAllocated = new AtomicInteger(0);
        /**
     * Does this servlet implement the SingleThreadModel interface?
     */
    protected volatile boolean singleThreadModel = false;
    /**
     * Maximum number of STM instances.
     */
    protected int maxInstances = 20;
    /**
     * Number of instances currently loaded for a STM servlet.
     */
    protected int nInstances = 0;
    //如果Servlet是单例模式,则返回instance
    //否则创建一个新的Servlet,push到instancePool中
     public Servlet allocate() throws ServletException {
        // If we are currently unloading this servlet, throw an exception
        if (unloading) {
            throw new ServletException(sm.getString("standardWrapper.unloading", getName()));
        }
        boolean newInstance = false;
        // If not SingleThreadedModel, return the same instance every time
        if (!singleThreadModel) {
            // Load and initialize our instance if necessary
            if (instance == null || !instanceInitialized) {
                synchronized (this) {
                    if (instance == null) {
                        try {
                           //实例为null,则加载Servlet
                            instance = loadServlet();
                            newInstance = true;
                            if (!singleThreadModel) {
                                // For non-STM, increment here to prevent a race
                                // condition with unload. Bug 43683, test case
                                // #3
				//Servlet实例数据加1
                                countAllocated.incrementAndGet();
                            }
                        } 
                    }
                    if (!instanceInitialized) {
                        initServlet(instance);
                    }
                }
            }
	    //如果是多例模式,默认为false
            if (singleThreadModel) {
                if (newInstance) {
                    // Have to do this outside of the sync above to prevent a
                    // possible deadlock
                    synchronized (instancePool) {
		        //如果是单例模式,则push到instancePool中
                        instancePool.push(instance);
                        nInstances++;
                    }
                }
            } else {
	       //如果是单例模式,直接返回
                if (log.isTraceEnabled()) {
                    log.trace("  Returning non-STM instance");
                }
                // For new instances, count will have been incremented at the
                // time of creation
                if (!newInstance) {
                    countAllocated.incrementAndGet();
                }
                return instance;
            }
        }
        synchronized (instancePool) {
            while (countAllocated.get() >= nInstances) {
                // Allocate a new instance if possible, or else wait
                if (nInstances < maxInstances) {
		    //如果目前实例数,小于最大实例数
                    try {
		        //加载一个新的Servlet,push到instancePool中
                        instancePool.push(loadServlet());
                        nInstances++;
                    } 
                } else {
                    try {
		     //否则等待
                        instancePool.wait();
                    } 
                }
            }
            if (log.isTraceEnabled()) {
                log.trace("  Returning allocated STM instance");
            }
            countAllocated.incrementAndGet();
            return instancePool.pop();
        }
    }
}

//从分析StrandardWrapper可以看出,从StrandardWrapper的allocate方法,看出,当Servlet是单线程模型是则直接返回instance,否则加载一个新的Servlet,push到Servlet栈instancePool中。
总结:
从上面可以分析得出每个Host关联一个StardardContext,StardardContext是根据Web.xml的配置,初始化欢迎界面,角色权限,初始参数,错误处理,Listener,Filter和Sevlet等。
在加载Servlet的过程中,通过反射,调用Servlet的init方法。每个StandardContext有多个StandardWrappe子容器,StandardWrappe关联一个StandardPileLine,StandardPileLine中装配这StandardWrappeValve,StandardWrappeValve处理HTTP请求,通过invoke(),在invoke中,同StandardWrappe的allocate方法获取Servlet实例instance,然后将Request,StandardWrapper,Servlet包装到ApplicationFilterChain,然后执行Filter的doFilter方法;在Filter的doFilter中,限制性filter操作,然后通过反射调用servlet的service方法。下篇文章将介绍ContextConfig

附:
//tld配置
public final class TldConfig  implements LifecycleListener {

    private static final String TLD_EXT = ".tld";
    private static final String WEB_INF = "/WEB-INF/";
    private static final String WEB_INF_LIB = "/WEB-INF/lib/";
    //监听事件
     public void lifecycleEvent(LifecycleEvent event) {
        // Identify the context we are associated with
        try {
            context = (Context) event.getLifecycle();
        } 
        if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {
            init();
        } else if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
            try {
                execute();
            } 
        } 
	//扫描所有的tld,lib,初始化
	public void execute() {
        long t1=System.currentTimeMillis();
        /*
         * Priority order of URIs required by spec is:
         * 1. J2EE platform taglibs - Tomcat doesn't provide these
         * 2. web.xml entries
         * 3. JARS in WEB-INF/lib & TLDs under WEB-INF (equal priority)
         * 4. Additional entries from the container
         * 
         * Keep processing order in sync with o.a.j.compiler.TldLocationsCache
         */
        // Stage 2 - web.xml entries
        tldScanWebXml();
        // Stage 3a - TLDs under WEB-INF (not lib or classes)
        tldScanResourcePaths(WEB_INF);
        // Stages 3b & 4
        JarScanner jarScanner = context.getJarScanner();
        TldJarScannerCallback tldCallBack = new TldJarScannerCallback();
        jarScanner.scan(context.getServletContext(), context.getLoader().getClassLoader(),
                tldCallBack, noTldJars);
        // Now add all the listeners we found to the listeners for this context
        String list[] = getTldListeners();
        for( int i=0; i<list.length; i++ ) {
            context.addApplicationListener(
                    new ApplicationListener(list[i], true));
        }
        long t2=System.currentTimeMillis();
        if( context instanceof StandardContext ) {
            ((StandardContext)context).setTldScanTime(t2-t1);
        }
    }
 }

//StandardContextValve
final class StandardContextValve extends ValveBase {
    /**
     * Select the appropriate child Wrapper to process this request,
     * based on the specified request URI.  If no matching Wrapper can
     * be found, return an appropriate HTTP error.
     */
    @Override
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {

        // Disallow any direct access to resources under WEB-INF or META-INF
        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;
        }
        // Select the Wrapper to be used for this Request
        Wrapper wrapper = request.getWrapper();
        if (wrapper == null || wrapper.isUnavailable()) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        // Acknowledge the request
        try {
            response.sendAcknowledgement();
        } 
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
        }
        wrapper.getPipeline().getFirst().invoke(request, response);
    }
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics