- 浏览: 980981 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
Tomcat的Host初始化(Context,Listener,Filter,Servlet):http://donald-draper.iteye.com/blog/2327174
Host作为Engine的子容器,在Host中有两个变量为StandardContext和
configClass,StandardContext在前文中我们已经讲过了,
现在我们,来看看org.apache.catalina.startup.ContextConfig都做了些什么?
从上面可以看出Lifecycle.AFTER_INIT_EVENT触发init方法,init方法,首先创建一个
解析Context.xml文件的Digester,然后待在Context.xml文件,由Digester去解析处理;
下面来看一下Lifecycle.BEFORE_START_EVENT触发的方法beforeStart:
从beforeStart方法,我们可以看出每个从ContextConfig,关联一个StandardContext,
而每个StandardContext都有一个父容器StandardHost。
下面来看Lifecycle.CONFIGURE_START_EVENT事件的触发方法configureStart
//处理Context的CONFIGURE_START_EVENT事件
}
//解析WEB.XML文件,如果存在global web.xml,则以WEB——INF/WEB.XML为准,及当前WEB
从上面可看出,webConfig主要是处理web.xml的解析,与全局web.xml(Context)融合的问题
下面看一下cofigStart方法中注解的处理applicationAnnotationsConfig:
查看WebAnnotationSet的loadApplicationAnnotations函数:
//处理Listener,Filter,Servet的class,field,method,的注解
从分析注解的配置可以看出,实际上就是先从Context获取Lisenters,Filters和Servlets,
然后分别处理Lisenters,Filters和Servlets的Class,Field和Method的注解。
下面来看Lifecycle.AFTER_START_EVENT事件的触发方法configureStart
//context设置docBase
总结:
从以上分析每个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配置文件类
//处理XML的Digester
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 (james@interobjective.com). 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); } }
发表评论
-
tomcat日志及log4j日志乱码
2017-04-26 15:00 5498Linux系统字符编码:http://www.cnblogs. ... -
SQL盲注的解决方案
2016-10-27 18:35 2570引起SQL盲注的原因:http://www-01.ibm.co ... -
Tomcat的HTTPS配置详解
2016-10-27 16:59 971HTTPS原理详解:http://blog.csdn.net/ ... -
Tomcat的StandardService,Executor初始化与启动
2016-10-13 09:15 1610Tomcat的Server初始化及启动过程:http://do ... -
Tomcat的JioEndPoint,处理HTTP请求
2016-10-12 19:02 1251Tomcat的Connector(Protocol,Coyot ... -
Tomcat的Connector(Protocol,CoyoteAdapterAdapter,AprEndPoint)初始化及请求处理过程
2016-10-12 16:46 1619Tomcat的Server初始化及启动过程:http://do ... -
Tomcat问题集
2016-10-09 17:50 809tcnative-1.dll: Can't load AMD ... -
Tomcat的Host初始化(Context,Listener,Filter,Servlet)
2016-09-27 08:42 1498Tomcat的Engine初始化,启动过程:http://do ... -
Tomcat的Engine初始化,启动过程
2016-09-26 15:33 2301Tomcat的Server初始化及启动过程:http://do ... -
Tomcat的Server初始化及启动过程
2016-09-26 11:02 2938Tomcat7,启动过程(BootStrap、Catalina ... -
Tomcat7,启动过程(BootStrap、Catalina)
2016-09-23 19:08 1861Tomcat 系统架构与设计模式,工作原理:http://ww ... -
405 request method post not supported
2016-08-18 18:09 32291.检查链接地址有没有错误 2.看RequestMethod, ... -
apache-tomcat-7.0.67\bin\tcnative-1.dll: Can't load AMD 64-bit .dll on a IA 3
2016-08-12 13:02 1125F:\apache-tomcat-7.0.67\bin\tcn ...
相关推荐
在 Web 应用程序中,事件监听器和过滤器可以在 web.xml 文件中进行配置,例如: <listener-class>com.example.MyServletContextListener</listener-class> 在上面的配置中,定义了一个名为 ...
在Spring MVC中,`org.springframework.web.context.ContextLoaderListener`是一个关键监听器,它实现了`ServletContextListener`接口。当Web应用程序启动时,Tomcat或Jetty等容器会触发此监听器,进而加载Spring的...
在Web应用启动时,容器(如Tomcat)会自动解析`web-config.xml`,并根据配置创建Servlet、过滤器和监听器实例,进行初始化和注册。这样,当请求到来时,容器能够根据配置执行相应的处理逻辑。 总结来说,解析`web-...
通过上述内容可以看出,`web.xml`文件涵盖了Web应用配置的各个方面,从简单的元数据到复杂的事件监听器和安全配置都有涉及。正确配置`web.xml`对于确保Web应用正常运行至关重要。开发者应当熟悉这些元素及其用途,...
- **listener**: 声明Web应用启动和终止时需要执行的监听器类。 - **filter**: 定义过滤器的配置信息,包括过滤器类的名称和URL模式映射。 - **filter-mapping**: 映射过滤器到具体的请求或请求模式。 - **servlet**...
`Web.xml`是Java Web应用程序中的核心配置文件,它用于配置应用程序的上下文信息、servlet映射、过滤器、监听器等关键组件。以下是对`Web.xml`中常见元素的详细解析: #### <web-app> - **作用**:根元素,所有...
本文档将深入探讨Tomcat中的两个核心配置文件:`web.xml`和`server.xml`,并提供详细的配置说明和实例。 ### 一、Tomcat介绍 1.1 **Tomcat简介** Tomcat是开源的Servlet容器,它实现了Java Servlet和JavaServer ...
`web.xml`文件是一个XML格式的配置文件,用于定义Servlet、过滤器(Filter)、监听器(Listener)、会话超时、错误页面等关键组件及其行为。它是Java Web应用程序的配置中心,为容器(如Tomcat)提供运行时环境的...
它主要用于定义应用程序级别的配置信息,包括但不限于 Servlet 的映射、过滤器(Filter)的配置、监听器(Listener)的配置以及一些上下文参数(Context Parameters)的设定等。 #### 二、web.xml 的作用 1. **欢迎页...
`web.xml`是Servlet容器(如Tomcat、Jetty等)启动时读取的配置文件,用于指导服务器如何处理Web应用中的请求和资源。通过这个文件,你可以设置初始化参数、映射Servlet、配置过滤器、声明安全约束等。 2. **基本...
web.xml文件是Java Web应用程序的部署描述符,它是容器(如Tomcat)理解和管理Web应用的关键配置文件。本文将深入探讨web.xml文件中的加载顺序和常用元素,帮助开发者更好地理解和使用。 首先,加载顺序是web.xml...
在 Tomcat 环境下,Web.XML 文件是必不可少的,用于配置 Web 应用程序的各种参数。本文将详细介绍 Web.XML 文件的配置详解。 一、定义头和根元素 在 Web.XML 文件中,必须以一个 XML 头开始,声明 XML 版本和字符...
`web.xml`是Java Web应用的核心配置文件,用于定义Servlet、过滤器、监听器以及其他相关组件的行为和配置。它是按照Servlet规范定义的标准格式编写,独立于任何特定的应用服务器,如Tomcat。以下是对`web.xml`文件中...
通过`<listener>`元素添加监听器,用于监听Web应用生命周期中的特定事件。 15. **J2EE元素** `web.xml`还可以包含J2EE规范定义的其他元素,用于实现更复杂的应用功能,如EJB、JMS、JNDI等。 以上是`web.xml`控制...
此文件位于WEB-INF目录下,被服务器用来解析Web应用的各种设置,如Servlet映射、过滤器配置、监听器注册等。下面将对`web.xml`中的关键元素进行详细介绍。 #### 1. `web-app` 这是`web.xml`的根元素,用于封装整个...
7. **listener**:Servlet API 2.3 版本增加了对事件监听器的支持,通过 `<listener>` 元素指出事件监听器类。 - 示例:`<listener><listener-class>com.example.MyListener</listener-class></listener>`。 8. **...
`web.xml`是Java Web应用的部署描述符,它定义了Servlet、过滤器和监听器等组件的配置。在与WebService相关的场景中,`web.xml`可能会包含以下内容: 1. **Servlet mappings**:配置用于处理WebService请求的...
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/config/...
2. **web.xml**: 也称为部署描述符,定义了Web应用的默认配置,如Servlet、过滤器、监听器等。 3. **tomcat-users.xml**: 管理员和角色的配置,用于控制对管理界面的访问权限。 4. **context.xml**: 应用级别的...