Tomcat源码解析(三):StandardContext

StandardContext是Catalina中的一个Container,负责处理用户请求并将其交给内部valve处理。它作为应用程序的容器,包含多个Wrapper,每个对应一个servlet。启动时,通过start()方法准备各种功能,请求到来时,Connector调用invoke()方法,由pipeline中的valve顺序处理。reload功能用于重新加载配置。理解其工作原理需要深入研究start()方法及其涉及的模块协同处理请求的过程。

StandardContext

Catalina主要包括Connector和Container,StandardContext就是一个Container,它主要负责对进入的用户请求进行处理。实际来说,不是由它来进行处理,而是交给内部的valve处理。
一个context表示了一个外部应用,它包含多个wrapper,每个wrapper表示一个servlet定义。

/**
 * Standard implementation of the <b>Context</b> interface.  Each
 * child container must be a Wrapper implementation to process the
 * requests directed to a particular servlet.
 *
 * @author Craig R. McClanahan
 * @author Remy Maucherat
 * @version $Revision: 1.112 $ $Date: 2002/09/09 14:39:37 $
 */

public class StandardContext
    extends ContainerBase
    implements Context {


    // ----------------------------------------------------------- Constructors
    /**
     * Create a new StandardContext component with the default basic Valve.
     */
    public StandardContext() {

        super();
        pipeline.setBasic(new StandardContextValve());
        namingResources.setContainer(this);

    }

StandardContext主要成员


/**
 * The application available flag for this Context.
 */
private boolean available = false;

/**
 * The "correctly configured" flag for this Context.
 * context是否已经正确设置完成
 */
private boolean configured = false;

/**
 * The document root for this web application.
 */
private String docBase = null;

/**
 * The set of filter definitions for this application, keyed by
 * filter name.
 * 过滤器定义
 */
private HashMap filterDefs = new HashMap();


/**
 * The set of filter mappings for this application, in the order
 * they were defined in the deployment descriptor.
 * 过滤器匹配
 */
private FilterMap filterMaps[] = new FilterMap[0];

/**
 * The login configuration descriptor for this web application.
 * 登陆权限验证
 */
private LoginConfig loginConfig = null;

  /**
 * The Java class name of the default Mapper class for this Container.
 */
private String mapperClass =
    "org.apache.catalina.core.StandardContextMapper";


/**
 * The security role mappings for this application, keyed by role
 * name (as used within the application).
 * 角色匹配。权限验证用到
 */
private HashMap roleMappings = new HashMap();


/**
 * The servlet mappings for this web application, keyed by
 * matching pattern.
 * servlet匹配。用于根据url等匹配对应servlet
 */
private HashMap servletMappings = new HashMap();

StandardContext.start()

项目启动时,启动Connector和Context,让各种功能就绪。


/**
 * Start this Context component.
 *
 * @exception LifecycleException if a startup error occurs
 */
public synchronized void start() throws LifecycleException {
    if (started)
        throw new LifecycleException
            (sm.getString("containerBase.alreadyStarted", logName()));

    if (debug >= 1)
        log("Starting");

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

    if (debug >= 1)
        log("Processing start(), current available=" + getAvailable());
    setAvailable(false);
    setConfigured(false);
    boolean ok = true;

    // Add missing components as necessary
    if (getResources() == null) {   // (1) Required by Loader
        if (debug >= 1)
            log("Configuring default Resources");
        try {
            if ((docBase != null) && (docBase.endsWith(".war")))
                setResources(new WARDirContext());
            else
                setResources(new FileDirContext());
        } catch (IllegalArgumentException e) {
            log("Error initializing resources: " + e.getMessage());
            ok = false;
        }
    }
    if (ok && (resources instanceof ProxyDirContext)) {
        DirContext dirContext =
            ((ProxyDirContext) resources).getDirContext();
        if ((dirContext != null)
            && (dirContext instanceof BaseDirContext)) {
            ((BaseDirContext) dirContext).setDocBase(getBasePath());
            ((BaseDirContext) dirContext).allocate();
        }
    }
    //类加载器
    if (getLoader() == null) {      // (2) Required by Manager
        if (getPrivileged()) {
            if (debug >= 1)
                log("Configuring privileged default Loader");
            setLoader(new WebappLoader(this.getClass().getClassLoader()));
        } else {
            if (debug >= 1)
                log("Configuring non-privileged default Loader");
            setLoader(new WebappLoader(getParentClassLoader()));
        }
    }
    //manager管理session
    if (getManager() == null) {     // (3) After prerequisites
        if (debug >= 1)
            log("Configuring default Manager");
        setManager(new StandardManager());
    }

    // Initialize character set mapper
    getCharsetMapper();

    // Post work directory
    postWorkDirectory();

    // 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.setDebug(getDebug());
            namingContextListener.setName(getNamingContextName());
            addLifecycleListener(namingContextListener);
        }
    }

    // Binding thread 这个功能是什么呢?
    ClassLoader oldCCL = bindThread();

    // Standard container startup
    if (debug >= 1)
        log("Processing standard container startup");

    if (ok) {

        try {

            addDefaultMapper(this.mapperClass);
            started = true;

            // Start our subordinate components, if any
            //启动loader和logger
            if ((loader != null) && (loader instanceof Lifecycle))
                ((Lifecycle) loader).start();
            if ((logger != null) && (logger instanceof Lifecycle))
                ((Lifecycle) logger).start();

            // Unbinding thread
            unbindThread(oldCCL);

            // Binding thread
            oldCCL = bindThread();

            if ((cluster != null) && (cluster instanceof Lifecycle))
                ((Lifecycle) cluster).start();
            //启动realm
            if ((realm != null) && (realm instanceof Lifecycle))
                ((Lifecycle) realm).start();
            if ((resources != null) && (resources instanceof Lifecycle))
                ((Lifecycle) resources).start();

            // Start our Mappers, if any
            Mapper mappers[] = findMappers();
            for (int i = 0; i < mappers.length; i++) {
                if (mappers[i] instanceof Lifecycle)
                    ((Lifecycle) mappers[i]).start();
            }

            // Start our child containers, if any 一般指wrapper
            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);

            if ((manager != null) && (manager instanceof Lifecycle))
                ((Lifecycle) manager).start();

        } finally {
            // Unbinding thread
            unbindThread(oldCCL);
        }

    }
    if (!getConfigured())
        ok = false;

    // We put the resources into the servlet context
    if (ok)
        getServletContext().setAttribute
            (Globals.RESOURCES_ATTR, getResources());

    // Binding thread
    oldCCL = bindThread();

    // Create context attributes that will be required
    if (ok) {
        if (debug >= 1)
            log("Posting standard context attributes");
        postWelcomeFiles();
    }

    // Configure and call application event listeners and filters
    if (ok) {
        if (!listenerStart())
            ok = false;
    }
    if (ok) {
        if (!filterStart())
            ok = false;
    }

    // Load and initialize all "load on startup" servlets
    if (ok)
        loadOnStartup(findChildren());

    // Unbinding thread
    unbindThread(oldCCL);

    // Set available status depending upon startup success
    if (ok) {
        if (debug >= 1)
            log("Starting completed");
        setAvailable(true);
    } else {
        log(sm.getString("standardContext.startFailed"));
        try {
            stop();
        } catch (Throwable t) {
            log(sm.getString("standardContext.startCleanup"), t);
        }
        setAvailable(false);
    }

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

}

/**
 * ******************* 这个是干啥的捏??????************************
 * 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;

    Thread.currentThread().setContextClassLoader
        (getLoader().getClassLoader());

    DirContextURLStreamHandler.bind(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;

}

StandardContext.invoke()

请求进入后,Connector调用context的invoke方法。invoke将请求交给其pipeline去处理,由pipeline中的所有valve顺序处理请求。


/**
 * Process the specified Request, and generate the corresponding Response,
 * according to the design of this particular Container.
 *
 * @param request Request to be processed
 * @param response Response to be produced
 *
 * @exception IOException if an input/output error occurred while
 *  processing
 * @exception ServletException if a ServletException was thrown
 *  while processing this request
 */
public void invoke(Request request, Response response)
    throws IOException, ServletException {

    // Wait if we are reloading
    while (getPaused()) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            ;
        }
    }

    // Normal request processing
    if (swallowOutput) {
        try {
            SystemLogHandler.startCapture();
            super.invoke(request, response);
        } finally {
            String log = SystemLogHandler.stopCapture();
            if (log != null && log.length() > 0) {
                log(log);
            }
        }
    } else {
        super.invoke(request, response);
    }

}

reload

总结

StandardContext是比较复杂的一块,像一个大容器,包括了类加载器、session管理、wrapper管理等模块,在启动时顺序启动这些模块。在请求进入时,由这些模块互相合作处理请求。所以start()是比较复杂的,这一块我花了好多时间看,还是不特别理解,只是知道了大致的流程。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值