Tomcat-ConfigContext监听器(Context.xml,web.xml)

Tomcat的Host初始化(Context,Listener,Filter,Servlet): http://donald-draper.iteye.com/blog/2327174
Host作为Engine的子容器,在Host中有两个变量为StandardContext和
configClass,StandardContext在前文中我们已经讲过了,
public class StandardHost extends ContainerBase implements Host {
/**
     * 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.
     */
    private String contextClass =
        "org.apache.catalina.core.StandardContext";
}

现在我们,来看看org.apache.catalina.startup.ContextConfig都做了些什么?
public class ContextConfig implements LifecycleListener {
 /**
     * The set of Authenticators that we know how to configure.  The key is
     * the name of the implemented authentication method, and the value is
     * the fully qualified Java class name of the corresponding Valve.
     */
 protected static final Properties authenticators;
   /**
     * The list of JARs that will be skipped when scanning a web application
     * for JARs. This means the JAR will not be scanned for web fragments, SCIs,
     * annotations or classes that match @HandlesTypes.
     */
    private static final Set<String> pluggabilityJarsToSkip =
            new HashSet<String>();

    static {
        // Load our mapping properties for the standard authenticators
        Properties props = new Properties();
        InputStream is = null;
        try {
	    //加载Authenticators.properties
            is = ContextConfig.class.getClassLoader().getResourceAsStream(
                    "org/apache/catalina/startup/Authenticators.properties");
            if (is != null) {
                props.load(is);
            }
        } 
        authenticators = props;
        //Load the list of JARS to skip
        addJarsToSkip(Constants.DEFAULT_JARS_TO_SKIP);
        addJarsToSkip(Constants.PLUGGABILITY_JARS_TO_SKIP);
    }
     /**
     * 每个Host的默认web.xml配置缓存
     */
    protected static final Map<Host,DefaultWebXmlCacheEntry> hostWebXmlCache =
        new ConcurrentHashMap<Host,DefaultWebXmlCacheEntry>();
     //当容器生命周期变化时,激发
     public void lifecycleEvent(LifecycleEvent event) {

        // Identify the context we are associated with
        try {
	   //获取Context
            context = (Context) event.getLifecycle();
        } 

        if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
	    //开始配置
            configureStart();
        } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
            beforeStart();
        } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
            //context设置docBase
            if (originalDocBase != null) {
                context.setDocBase(originalDocBase);
            }
        } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {
            configureStop();
        } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {
	    //初始化
            init();
        } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {
            destroy();
        }
       //处理Context的AFTER_INIT_EVENT事件
       protected void init() {
        // Called from StandardContext.init()
	//创建一个解析Context.xml的Digester
        Digester contextDigester = createContextDigester();
        contextDigester.getParser();
        if (log.isDebugEnabled())
            log.debug(sm.getString("contextConfig.init"));
        context.setConfigured(false);
        ok = true;
	//解析Context.xml文件
        contextConfig(contextDigester);
        createWebXmlDigester(context.getXmlNamespaceAware(),
                context.getXmlValidation());
    }
    //获取Context.xml,与Digester关联
    protected void contextConfig(Digester digester) {

        // Open the default context.xml file, if it exists
        if( defaultContextXml==null && context instanceof StandardContext ) {
            defaultContextXml = ((StandardContext)context).getDefaultContextXml();
        }
        // set the default if we don't have any overrides
        if( defaultContextXml==null ) getDefaultContextXml();

        if (!context.getOverride()) {
            File defaultContextFile = new File(defaultContextXml);
            if (!defaultContextFile.isAbsolute()) {
                defaultContextFile =new File(getBaseDir(), defaultContextXml);
            }
            if (defaultContextFile.exists()) {
                try {
                    URL defaultContextUrl = defaultContextFile.toURI().toURL();
                    processContextConfig(digester, defaultContextUrl);
                } catch (MalformedURLException e) {
                    log.error(sm.getString(
                            "contextConfig.badUrl", defaultContextFile), e);
                }
            }

            File hostContextFile = new File(getHostConfigBase(), Constants.HostContextXml);
            if (hostContextFile.exists()) {
                try {
                    URL hostContextUrl = hostContextFile.toURI().toURL();
                    processContextConfig(digester, hostContextUrl);
                } catch (MalformedURLException e) {
                    log.error(sm.getString(
                            "contextConfig.badUrl", hostContextFile), e);
                }
            }
        }
        if (context.getConfigFile() != null)
            processContextConfig(digester, context.getConfigFile());

    }
    //处理context.xml.
    protected void processContextConfig(Digester digester, URL contextXml) {
        if (log.isDebugEnabled())
            log.debug("Processing context [" + context.getName()
                    + "] configuration file [" + contextXml + "]");
        InputSource source = null;
        InputStream stream = null;
        try {
            source = new InputSource(contextXml.toString());
            URLConnection xmlConn = contextXml.openConnection();
            xmlConn.setUseCaches(false);
            stream = xmlConn.getInputStream();
	    }
        try {
            source.setByteStream(stream);
            digester.setClassLoader(this.getClass().getClassLoader());
            digester.setUseContextClassLoader(false);
            digester.push(context.getParent());
            digester.push(context);
            XmlErrorHandler errorHandler = new XmlErrorHandler();
            digester.setErrorHandler(errorHandler);
            digester.parse(source);
            if (log.isDebugEnabled()) {
                log.debug("Successfully processed context [" + context.getName()
                        + "] configuration file [" + contextXml + "]");
            }
        } 
    }
 }

从上面可以看出Lifecycle.AFTER_INIT_EVENT触发init方法,init方法,首先创建一个
解析Context.xml文件的Digester,然后待在Context.xml文件,由Digester去解析处理;
下面来看一下Lifecycle.BEFORE_START_EVENT触发的方法beforeStart:
//Process a "before start" event for this Context.
protected synchronized void beforeStart() {
        try {
	    //调整docBase.
            fixDocBase();
        } 
	 //调整antiLockingDocBase
        antiLocking();
    }
    //调整docBase.
    protected void fixDocBase()
        throws IOException {
	//获取StandardHost
        Host host = (Host) context.getParent();
        String appBase = host.getAppBase();
        File canonicalAppBase = new File(appBase);
        if (canonicalAppBase.isAbsolute()) {
            canonicalAppBase = canonicalAppBase.getCanonicalFile();
        } else {
            canonicalAppBase =
                new File(getBaseDir(), appBase)
                .getCanonicalFile();
        }
        String docBase = context.getDocBase();
        if (docBase == null) {
            // Trying to guess the docBase according to the path
            String path = context.getPath();
            if (path == null) {
                return;
            }
            ContextName cn = new ContextName(path, context.getWebappVersion());
            docBase = cn.getBaseName();
        }
        File file = new File(docBase);
        if (!file.isAbsolute()) {
            docBase = (new File(canonicalAppBase, docBase)).getPath();
        } else {
            docBase = file.getCanonicalPath();
        }
        file = new File(docBase);
        String origDocBase = docBase;
        ContextName cn = new ContextName(context.getPath(),
                context.getWebappVersion());
        String pathName = cn.getBaseName();
        boolean unpackWARs = true;
        if (host instanceof StandardHost) {
            unpackWARs = ((StandardHost) host).isUnpackWARs();
            if (unpackWARs && context instanceof StandardContext) {
                unpackWARs =  ((StandardContext) context).getUnpackWAR();
            }
        }
        if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory()) {
            URL war = UriUtil.buildJarUrl(new File(docBase));
            if (unpackWARs) {
                docBase = ExpandWar.expand(host, war, pathName);
                file = new File(docBase);
                docBase = file.getCanonicalPath();
                if (context instanceof StandardContext) {
		    //设置StandardContext的docBase
                    ((StandardContext) context).setOriginalDocBase(origDocBase);
                }
            } else {
                ExpandWar.validate(host, war, pathName);
            }
        } else {
            File docDir = new File(docBase);
            if (!docDir.exists()) {
                File warFile = new File(docBase + ".war");
                if (warFile.exists()) {
                    URL war = UriUtil.buildJarUrl(warFile);
                    if (unpackWARs) {
                        docBase = ExpandWar.expand(host, war, pathName);
                        file = new File(docBase);
                        docBase = file.getCanonicalPath();
                    } else {
                        docBase = warFile.getCanonicalPath();
                        ExpandWar.validate(host, war, pathName);
                    }
                }
                if (context instanceof StandardContext) {
                    ((StandardContext) context).setOriginalDocBase(origDocBase);
                }
            }
        }
        context.setDocBase(docBase);

    }
    //调整antiLockingDocBase
    protected void antiLocking() {

        if ((context instanceof StandardContext)
            && ((StandardContext) context).getAntiResourceLocking()) {

            Host host = (Host) context.getParent();
            String appBase = host.getAppBase();
            String docBase = context.getDocBase();
            originalDocBase = docBase;
            File docBaseFile = new File(docBase);
            if (!docBaseFile.isAbsolute()) {
                File file = new File(appBase);
                if (!file.isAbsolute()) {
                    file = new File(getBaseDir(), appBase);
                }
                docBaseFile = new File(file, docBase);
            }
            String path = context.getPath();
            ContextName cn = new ContextName(path, context.getWebappVersion());
            docBase = cn.getBaseName();
            if (originalDocBase.toLowerCase(Locale.ENGLISH).endsWith(".war")) {
                antiLockingDocBase = new File(
                        System.getProperty("java.io.tmpdir"),
                        deploymentCount++ + "-" + docBase + ".war");
            } else {
                antiLockingDocBase = new File(
                        System.getProperty("java.io.tmpdir"),
                        deploymentCount++ + "-" + docBase);
            }
            antiLockingDocBase = antiLockingDocBase.getAbsoluteFile();

            if (log.isDebugEnabled())
                log.debug("Anti locking context[" + context.getName()
                        + "] setting docBase to " +
                        antiLockingDocBase.getPath());

            // Cleanup just in case an old deployment is lying around
            ExpandWar.delete(antiLockingDocBase);
            if (ExpandWar.copy(docBaseFile, antiLockingDocBase)) {
                context.setDocBase(antiLockingDocBase.getPath());
            }
        }
    }

从beforeStart方法,我们可以看出每个从ContextConfig,关联一个StandardContext,
而每个StandardContext都有一个父容器StandardHost。
下面来看Lifecycle.CONFIGURE_START_EVENT事件的触发方法configureStart
//处理Context的CONFIGURE_START_EVENT事件
    protected synchronized void configureStart() {
        // Called from StandardContext.start()
        if (log.isDebugEnabled())
            log.debug(sm.getString("contextConfig.start"));
        //扫描Web.xml文件,应用到web
        webConfig();
        if (!context.getIgnoreAnnotations()) {
	    //处理Listener,Filter,Servet的class,field,method,
	    //EJB,JSR 250类注解问题,@Resource等注解
            applicationAnnotationsConfig();
        }
        if (ok) {
	    //配置安全角色信息
            validateSecurityRoles();
        }
        // Configure an authenticator if we need one
        if (ok)
            authenticatorConfig();
        // Dump the contents of this pipeline if requested
        if ((log.isDebugEnabled()) && (context instanceof ContainerBase)) {
            log.debug("Pipeline Configuration:");
            Pipeline pipeline = ((ContainerBase) context).getPipeline();
            Valve valves[] = null;
            if (pipeline != null)
                valves = pipeline.getValves();
            if (valves != null) {
                for (int i = 0; i < valves.length; i++) {
                    log.debug("  " + valves[i].getInfo());
                }
            }
            log.debug("======================");
        }
        // Make our application available if no problems were encountered
        if (ok)
            context.setConfigured(true);
        else {
            log.error(sm.getString("contextConfig.unavailable"));
            context.setConfigured(false);
        }

}
//解析WEB.XML文件,如果存在global web.xml,则以WEB——INF/WEB.XML为准,及当前WEB
    protected void webConfig() {
        Set<WebXml> defaults = new HashSet<WebXml>();
        //从Host获取默认WebXML,通过Digester解析,添加到defaults
        defaults.add(getDefaultWebXmlFragment());
        WebXml webXml = createWebXml();
        //解析全局Web.xml
        // Parse context level web.xml
        InputSource contextWebXml = getContextWebXmlSource();
        parseWebXml(contextWebXml, webXml, false);

        ServletContext sContext = context.getServletContext();

        // Ordering is important here

        // Step 1. Identify all the JARs packaged with the application
        // If the JARs have a web-fragment.xml it will be parsed at this
        // point.
        Map<String,WebXml> fragments = processJarsForWebFragments(webXml);

        // Step 2. Order the fragments.
        Set<WebXml> orderedFragments = null;
        orderedFragments =
                WebXml.orderWebFragments(webXml, fragments, sContext);

        // Step 3. Look for ServletContainerInitializer implementations
        if (ok) {
            processServletContainerInitializers();
        }

        if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
            // Step 4. Process /WEB-INF/classes for annotations
            if (ok) {
                // Hack required by Eclipse's "serve modules without
                // publishing" feature since this backs WEB-INF/classes by
                // multiple locations rather than one.
                NamingEnumeration<Binding> listBindings = null;
                try {
                    try {
                        listBindings = context.getResources().listBindings(
                                "/WEB-INF/classes");
                    } 
                    while (listBindings != null &&
                            listBindings.hasMoreElements()) {
                        Binding binding = listBindings.nextElement();
                        if (binding.getObject() instanceof FileDirContext) {
                            File webInfClassDir = new File(
                                    ((FileDirContext) binding.getObject()).getDocBase());
                            processAnnotationsFile(webInfClassDir, webXml,
                                    webXml.isMetadataComplete());
                        } else {
                            String resource =
                                    "/WEB-INF/classes/" + binding.getName();
                            try {
                                URL url = sContext.getResource(resource);
                                processAnnotationsUrl(url, webXml,
                                        webXml.isMetadataComplete());
                            } 
                        }
                    }
                } 
            }

            // Step 5. Process JARs for annotations - only need to process
            // those fragments we are going to use
            if (ok) {
                processAnnotations(
                        orderedFragments, webXml.isMetadataComplete());
            }

            // Cache, if used, is no longer required so clear it
            javaClassCache.clear();
        }

        if (!webXml.isMetadataComplete()) {
            // Step 6. Merge web-fragment.xml files into the main web.xml
            // file.
            if (ok) {
                ok = webXml.merge(orderedFragments);
            }

            // Step 7. Apply global defaults
            // Have to merge defaults before JSP conversion since defaults
            // provide JSP servlet definition.
            webXml.merge(defaults);

            // Step 8. Convert explicitly mentioned jsps to servlets
            if (ok) {
                convertJsps(webXml);
            }

            // Step 9. Apply merged web.xml to Context
            if (ok) {
                webXml.configureContext(context);
            }
        } else {
            webXml.merge(defaults);
            convertJsps(webXml);
            webXml.configureContext(context);
        }

        // Step 9a. Make the merged web.xml available to other
        // components, specifically Jasper, to save those components
        // from having to re-generate it.
        // TODO Use a ServletContainerInitializer for Jasper
        String mergedWebXml = webXml.toXml();
        sContext.setAttribute(
               org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML,
               mergedWebXml);
        if (context.getLogEffectiveWebXml()) {
            log.info("web.xml:\n" + mergedWebXml);
        }

        // Always need to look for static resources
        // Step 10. Look for static resources packaged in JARs
        if (ok) {
            // Spec does not define an order.
            // Use ordered JARs followed by remaining JARs
            Set<WebXml> resourceJars = new LinkedHashSet<WebXml>();
            for (WebXml fragment : orderedFragments) {
                resourceJars.add(fragment);
            }
            for (WebXml fragment : fragments.values()) {
                if (!resourceJars.contains(fragment)) {
                    resourceJars.add(fragment);
                }
            }
            processResourceJARs(resourceJars);
            // See also StandardContext.resourcesStart() for
            // WEB-INF/classes/META-INF/resources configuration
        }

        // Step 11. Apply the ServletContainerInitializer config to the
        // context
        if (ok) {
            for (Map.Entry<ServletContainerInitializer,
                    Set<Class<?>>> entry :
                        initializerClassMap.entrySet()) {
                if (entry.getValue().isEmpty()) {
                    context.addServletContainerInitializer(
                            entry.getKey(), null);
                } else {
                    context.addServletContainerInitializer(
                            entry.getKey(), entry.getValue());
                }
            }
        }
    }

从上面可看出,webConfig主要是处理web.xml的解析,与全局web.xml(Context)融合的问题
下面看一下cofigStart方法中注解的处理applicationAnnotationsConfig:
// Process the application classes annotations, if it exists.
    protected void applicationAnnotationsConfig() {
        long t1=System.currentTimeMillis();
        WebAnnotationSet.loadApplicationAnnotations(context);
        long t2=System.currentTimeMillis();
        if (context instanceof StandardContext) {
            ((StandardContext) context).setStartupTime(t2-t1+
                    ((StandardContext) context).getStartupTime());
        }
    }

查看WebAnnotationSet的loadApplicationAnnotations函数:
//处理Listener,Filter,Servet的class,field,method,的注解
 public static void loadApplicationAnnotations(Context context) {
        loadApplicationListenerAnnotations(context);
        loadApplicationFilterAnnotations(context);
        loadApplicationServletAnnotations(context);
    }
//处理Listener的注解
    protected static void loadApplicationListenerAnnotations(Context context) {
        Class<?> classClass = null;
	//从Context获取applicationListeners
        String[] applicationListeners =
                context.findApplicationListeners();
        for (int i = 0; i < applicationListeners.length; i++) {
            classClass = Introspection.loadClass(context,
                    applicationListeners[i]);
            if (classClass == null) {
                continue;
            }
	    //处理Listener的class,field,method,的注解
            loadClassAnnotation(context, classClass);
            loadFieldsAnnotation(context, classClass);
            loadMethodsAnnotation(context, classClass);
        }
}
//处理Filter的注解
    protected static void loadApplicationFilterAnnotations(Context context) {
        Class<?> classClass = null;
        FilterDef[] filterDefs = context.findFilterDefs();
        for (int i = 0; i < filterDefs.length; i++) {
            classClass = Introspection.loadClass(context,
                    (filterDefs[i]).getFilterClass());
            if (classClass == null) {
                continue;
            }
            //处理Filter的class,field,method,的注解
            loadClassAnnotation(context, classClass);
            loadFieldsAnnotation(context, classClass);
            loadMethodsAnnotation(context, classClass);
        }
    }
//处理Server的注解
    protected static void loadApplicationServletAnnotations(Context context) {
        
        Wrapper wrapper = null;
        Class<?> classClass = null;
        Container[] children = context.findChildren();
        for (int i = 0; i < children.length; i++) {
            if (children[i] instanceof Wrapper) {
                
                wrapper = (Wrapper) children[i];
                if (wrapper.getServletClass() == null) {
                    continue;
                }
                classClass = Introspection.loadClass(context,
                        wrapper.getServletClass());
                if (classClass == null) {
                    continue;
                }
                //处理Servet的class,field,method,的注解
                loadClassAnnotation(context, classClass);
                loadFieldsAnnotation(context, classClass);
                loadMethodsAnnotation(context, classClass);
                /* Process RunAs annotation which can be only on servlets.
                 * Ref JSR 250, equivalent to the run-as element in
                 * the deployment descriptor
                 */
                RunAs annotation = classClass.getAnnotation(RunAs.class);
                if (annotation != null) {
                    wrapper.setRunAs(annotation.value());
                }
            }
        }
        
    }
//处理Listener的class,field,method,的注解
    protected static void loadClassAnnotation(Context context,
            Class<?> classClass) {
        /* Process Resource annotation.
         * Ref JSR 250
         */
        {
            Resource annotation = classClass.getAnnotation(Resource.class);
            if (annotation != null) {
                addResource(context, annotation);
            }
        }
        /* Process Resources annotation.
         * Ref JSR 250
         */
        {
	     //@Resource
            Resources annotation = classClass.getAnnotation(Resources.class);
            if (annotation != null && annotation.value() != null) {
                for (Resource resource : annotation.value()) {
                    addResource(context, resource);
                }
            }
        }
        /* Process EJB annotation.
         * Ref JSR 224, equivalent to the ejb-ref or ejb-local-ref
         * element in the deployment descriptor.
        {
	    //@EJB
            EJB annotation = classClass.getAnnotation(EJB.class);
            if (annotation != null) {

                if ((annotation.mappedName().length() == 0)
                        || annotation.mappedName().equals("Local")) {

                    ContextLocalEjb ejb = new ContextLocalEjb();

                    ejb.setName(annotation.name());
                    ejb.setType(annotation.beanInterface().getCanonicalName());
                    ejb.setDescription(annotation.description());

                    ejb.setHome(annotation.beanName());

                    context.getNamingResources().addLocalEjb(ejb);

                } else if (annotation.mappedName().equals("Remote")) {

                    ContextEjb ejb = new ContextEjb();

                    ejb.setName(annotation.name());
                    ejb.setType(annotation.beanInterface().getCanonicalName());
                    ejb.setDescription(annotation.description());

                    ejb.setHome(annotation.beanName());

                    context.getNamingResources().addEjb(ejb);

                }
            }
        }
        */
        /* Process WebServiceRef annotation.
         * Ref JSR 224, equivalent to the service-ref element in 
         * the deployment descriptor.
         * The service-ref registration is not implemented
        {
	    //@WebServiceRef
            WebServiceRef annotation = classClass
                    .getAnnotation(WebServiceRef.class);
            if (annotation != null) {
                ContextService service = new ContextService();

                service.setName(annotation.name());
                service.setWsdlfile(annotation.wsdlLocation());

                service.setType(annotation.type().getCanonicalName());

                if (annotation.value() == null)
                    service.setServiceinterface(annotation.type()
                            .getCanonicalName());

                if (annotation.type().getCanonicalName().equals("Service"))
                    service.setServiceinterface(annotation.type()
                            .getCanonicalName());

                if (annotation.value().getCanonicalName().equals("Endpoint"))
                    service.setServiceendpoint(annotation.type()
                            .getCanonicalName());

                service.setPortlink(annotation.type().getCanonicalName());

                context.getNamingResources().addService(service);
            }
        }
        */
        /* Process DeclareRoles annotation.
         * Ref JSR 250, equivalent to the security-role element in
         * the deployment descriptor
         */
        {
	    //@DeclareRoles
            DeclareRoles annotation = classClass
                    .getAnnotation(DeclareRoles.class);
            if (annotation != null && annotation.value() != null) {
                for (String role : annotation.value()) {
                    context.addSecurityRole(role);
                }
            }
        }
    }
   //处理field注解
    protected static void loadFieldsAnnotation(Context context,
            Class<?> classClass) {
        // Initialize the annotations
        Field[] fields = Introspection.getDeclaredFields(classClass);
        if (fields != null && fields.length > 0) {
            for (Field field : fields) {
	         //@Resource
                Resource annotation = field.getAnnotation(Resource.class);
                if (annotation != null) {
                    String defaultName = classClass.getName() + SEPARATOR + field.getName();
                    Class<?> defaultType = field.getType();
                    addResource(context, annotation, defaultName, defaultType);
                }
            }
        }
    }
    //处理method注解
    protected static void loadMethodsAnnotation(Context context,
            Class<?> classClass) {
        // Initialize the annotations
        Method[] methods = Introspection.getDeclaredMethods(classClass);
        if (methods != null && methods.length > 0) {
            for (Method method : methods) {
	        //@Resource
                Resource annotation = method.getAnnotation(Resource.class);
                if (annotation != null) {
                    if (!Introspection.isValidSetter(method)) {
                        throw new IllegalArgumentException(sm.getString(
                                "webAnnotationSet.invalidInjection"));
                    }
                    String defaultName = classClass.getName() + SEPARATOR +
                            Introspection.getPropertyName(method);

                    Class<?> defaultType =
                            (method.getParameterTypes()[0]);
                    addResource(context, annotation, defaultName, defaultType);
                }
            }
        }
    }

从分析注解的配置可以看出,实际上就是先从Context获取Lisenters,Filters和Servlets,
然后分别处理Lisenters,Filters和Servlets的Class,Field和Method的注解。
下面来看Lifecycle.AFTER_START_EVENT事件的触发方法configureStart
//context设置docBase
 if (originalDocBase != null) {
       context.setDocBase(originalDocBase);
 }

总结:
从以上分析每个Host,关联一个ContextConfig和StandardContext,而ContextConfig关联于StandardContext;ContextConfig其实是一个LifecycleListener可以监听StandardContext容器的声明周期变化;当处于AFTER_INIT_EVEN状态时,加载Context.xml文件,通过Digester解析;当处于BEFORE_START_EVENT状态时,docbase;当处于CONFIGURE_START_EVENT状态时,加载Web.xml配置(欢迎页面,参数,listeners,filters,Servlet,filters-Maping,Servlet-Maping,SessionConfig,errorPage等),然后处理listeners,filters,Servlet的注解等;当处于AFTER_START_EVENT状态时,设置context的docBase,自此完成web应用的context.xml,web.xml的初始化工作。

附:
//Web.xml配置文件类
/**
 * Representation of common elements of web.xml and web-fragment.xml. Provides
 * a repository for parsed data before the elements are merged.
 * Validation is spread between multiple classes:
 * The digester checks for structural correctness (eg single login-config)
 * This class checks for invalid duplicates (eg filter/servlet names)
 * StandardContext will check validity of values (eg URL formats etc)
 */
 public class WebXml {
 // context-param
    // TODO: description (multiple with language) is ignored
    private Map<String,String> contextParams = new HashMap<String,String>();
    public void addContextParam(String param, String value) {
        contextParams.put(param, value);
    }
    public Map<String,String> getContextParams() { return contextParams; }

    // filter
    // TODO: Should support multiple description elements with language
    // TODO: Should support multiple display-name elements with language
    // TODO: Should support multiple icon elements
    // TODO: Description for init-param is ignored
    private Map<String,FilterDef> filters =
        new LinkedHashMap<String,FilterDef>();
   //添加Filter
    public void addFilter(FilterDef filter) {
        if (filters.containsKey(filter.getFilterName())) {
            // Filter names must be unique within a web(-fragment).xml
            throw new IllegalArgumentException(
                    sm.getString("webXml.duplicateFilter",
                            filter.getFilterName()));
        }
        filters.put(filter.getFilterName(), filter);
    }
    public Map<String,FilterDef> getFilters() { return filters; }

    // filter-mapping
    private Set<FilterMap> filterMaps = new LinkedHashSet<FilterMap>();
    private Set<String> filterMappingNames = new HashSet<String>();
    //添加FilterMaping
    public void addFilterMapping(FilterMap filterMap) {
        filterMaps.add(filterMap);
        filterMappingNames.add(filterMap.getFilterName());
    }
    public Set<FilterMap> getFilterMappings() { return filterMaps; }

    // listener
    // TODO: description (multiple with language) is ignored
    // TODO: display-name (multiple with language) is ignored
    // TODO: icon (multiple) is ignored
    private Set<String> listeners = new LinkedHashSet<String>();
    //添加Listeners
    public void addListener(String className) {
        listeners.add(className);
    }
    public Set<String> getListeners() { return listeners; }

    // servlet
    // TODO: description (multiple with language) is ignored
    // TODO: display-name (multiple with language) is ignored
    // TODO: icon (multiple) is ignored
    // TODO: init-param/description (multiple with language) is ignored
    // TODO: security-role-ref/description (multiple with language) is ignored
    private Map<String,ServletDef> servlets = new HashMap<String,ServletDef>();
    //添加Servlet
    public void addServlet(ServletDef servletDef) {
        servlets.put(servletDef.getServletName(), servletDef);
        if (overridable) {
            servletDef.setOverridable(overridable);
        }
    }
    public Map<String,ServletDef> getServlets() { return servlets; }

    // servlet-mapping
    private Map<String,String> servletMappings = new HashMap<String,String>();
    private Set<String> servletMappingNames = new HashSet<String>();
    //添加Servlet-mapping
    public void addServletMapping(String urlPattern, String servletName) {
        String oldServletName = servletMappings.put(urlPattern, servletName);
        if (oldServletName != null) {
            // Duplicate mapping. As per clarification from the Servlet EG,
            // deployment should fail.
            throw new IllegalArgumentException(sm.getString(
                    "webXml.duplicateServletMapping", oldServletName,
                    servletName, urlPattern));
        }
        servletMappingNames.add(servletName);
    }
    public Map<String,String> getServletMappings() { return servletMappings; }

    // session-config
    // Digester will check there is only one of these
    private SessionConfig sessionConfig = new SessionConfig();
    public void setSessionConfig(SessionConfig sessionConfig) {
        this.sessionConfig = sessionConfig;
    }
    public SessionConfig getSessionConfig() { return sessionConfig; }

    // mime-mapping
    private Map<String,String> mimeMappings = new HashMap<String,String>();
    public void addMimeMapping(String extension, String mimeType) {
        mimeMappings.put(extension, mimeType);
    }
    public Map<String,String> getMimeMappings() { return mimeMappings; }
 // welcome-file-list
    private Set<String> welcomeFiles = new LinkedHashSet<String>();
    public void addWelcomeFile(String welcomeFile) {
        if (replaceWelcomeFiles) {
            welcomeFiles.clear();
            replaceWelcomeFiles = false;
        }
        welcomeFiles.add(welcomeFile);
    }
    public Set<String> getWelcomeFiles() { return welcomeFiles; }

    // error-page
    private Map<String,ErrorPage> errorPages = new HashMap<String,ErrorPage>();
    public void addErrorPage(ErrorPage errorPage) {
        errorPages.put(errorPage.getName(), errorPage);
    }
    public Map<String,ErrorPage> getErrorPages() { return errorPages; }

    // Digester will check there is only one jsp-config
    // jsp-config/taglib or taglib (2.3 and earlier)
    private Map<String,String> taglibs = new HashMap<String,String>();
    public void addTaglib(String uri, String location) {
        if (taglibs.containsKey(uri)) {
            // Taglib URIs must be unique within a web(-fragment).xml
            throw new IllegalArgumentException(
                    sm.getString("webXml.duplicateTaglibUri", uri));
        }
        taglibs.put(uri, location);
    }
    public Map<String,String> getTaglibs() { return taglibs; }

    // jsp-config/jsp-property-group
    private Set<JspPropertyGroup> jspPropertyGroups =
        new LinkedHashSet<JspPropertyGroup>();
    public void addJspPropertyGroup(JspPropertyGroup propertyGroup) {
        jspPropertyGroups.add(propertyGroup);
    }
    public Set<JspPropertyGroup> getJspPropertyGroups() {
        return jspPropertyGroups;
    }

    // security-constraint
    // TODO: Should support multiple display-name elements with language
    // TODO: Should support multiple description elements with language
    private Set<SecurityConstraint> securityConstraints =
        new HashSet<SecurityConstraint>();
    public void addSecurityConstraint(SecurityConstraint securityConstraint) {
        securityConstraints.add(securityConstraint);
    }
    public Set<SecurityConstraint> getSecurityConstraints() {
        return securityConstraints;
    }

    // login-config
    // Digester will check there is only one of these
    private LoginConfig loginConfig = null;
    public void setLoginConfig(LoginConfig loginConfig) {
        this.loginConfig = loginConfig;
    }
    public LoginConfig getLoginConfig() { return loginConfig; }

    // security-role
    // TODO: description (multiple with language) is ignored
    private Set<String> securityRoles = new HashSet<String>();
    public void addSecurityRole(String securityRole) {
        securityRoles.add(securityRole);
    }
    public Set<String> getSecurityRoles() { return securityRoles; }


    // resource-ref
    // TODO: Should support multiple description elements with language
    private Map<String,ContextResource> resourceRefs =
        new HashMap<String,ContextResource>();
    public void addResourceRef(ContextResource resourceRef) {
        if (resourceRefs.containsKey(resourceRef.getName())) {
            // resource-ref names must be unique within a web(-fragment).xml
            throw new IllegalArgumentException(
                    sm.getString("webXml.duplicateResourceRef",
                            resourceRef.getName()));
        }
        resourceRefs.put(resourceRef.getName(), resourceRef);
    }
    public Map<String,ContextResource> getResourceRefs() {
        return resourceRefs;
    }

    // resource-env-ref
    // TODO: Should support multiple description elements with language
    private Map<String,ContextResourceEnvRef> resourceEnvRefs =
        new HashMap<String,ContextResourceEnvRef>();
    public void addResourceEnvRef(ContextResourceEnvRef resourceEnvRef) {
        if (resourceEnvRefs.containsKey(resourceEnvRef.getName())) {
            // resource-env-ref names must be unique within a web(-fragment).xml
            throw new IllegalArgumentException(
                    sm.getString("webXml.duplicateResourceEnvRef",
                            resourceEnvRef.getName()));
        }
        resourceEnvRefs.put(resourceEnvRef.getName(), resourceEnvRef);
    }
    public Map<String,ContextResourceEnvRef> getResourceEnvRefs() {
        return resourceEnvRefs;
    }
}

//处理XML的Digester
public class Digester extends DefaultHandler2 {
     /**
     * The parameters stack being utilized by CallMethodRule and
     * CallParamRule rules.
     */
    protected ArrayStack<Object> params = new ArrayStack<Object>();
    /**
     * The stack of body text string buffers for surrounding elements.
     */
    protected ArrayStack<StringBuilder> bodyTexts =
        new ArrayStack<StringBuilder>();

    /**
     * Construct a new Digester with default properties.
     */
    public Digester() {
        super();
    }
    /**
     * Construct a new Digester, allowing a SAXParser to be passed in.  This
     * allows Digester to be used in environments which are unfriendly to
     * JAXP1.1 (such as WebLogic 6.0).  Thanks for the request to change go to
     * James House ([email protected]).  This may help in places where
     * you are able to load JAXP 1.1 classes yourself.
     */
    public Digester(SAXParser parser) {
        super();
        this.parser = parser;
    }
    /**
     * Construct a new Digester, allowing an XMLReader to be passed in.  This
     * allows Digester to be used in environments which are unfriendly to
     * JAXP1.1 (such as WebLogic 6.0).  Note that if you use this option you
     * have to configure namespace and validation support yourself, as these
     * properties only affect the SAXParser and empty constructor.
     */
    public Digester(XMLReader reader) {
        super();
        this.reader = reader;
    }
    /**
     * Push a new object onto the top of the object stack.
     *
     * @param object The new object
     */
    public void push(Object object) {

        if (stack.size() == 0) {
            root = object;
        }
        stack.push(object);

    }

    /**
     * Pushes the given object onto the stack with the given name.
     * If no stack already exists with the given name then one will be created.
     * 
     * @param stackName the name of the stack onto which the object should be pushed
     * @param value the Object to be pushed onto the named stack.
     *
     * @since 1.6
     */
    public void push(String stackName, Object value) {
        ArrayStack<Object> namedStack = stacksByName.get(stackName);
        if (namedStack == null) {
            namedStack = new ArrayStack<Object>();
            stacksByName.put(stackName, namedStack);
        }
        namedStack.push(value);
    }
}

猜你喜欢

转载自donald-draper.iteye.com/blog/2327269
今日推荐