1 | <context-param> <param-name>webAppRootKey</param-name> <param-value>task.root</param-value> </context-param> <!-- 定義SPRING配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/taskContext*.xml</param-value> </context-param> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/log4j.properties</param-value> </context-param> <!-- 定義LOG4J監(jiān)聽器 --> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> ? <!-- 定義SPRING監(jiān)聽器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> |
進(jìn)入contextLoaderListener看看到底加載時做了甚么
==>org.springframework.web.context.ContextLoaderListener
1 | publicclass ContextLoaderListener implements ServletContextListener { ? private ContextLoader contextLoader; ? /** * Initialize the root web application context. *///當(dāng)WEB上下文初始化時,系統(tǒng)會調(diào)用此方法publicvoid contextInitialized(ServletContextEvent event) { this.contextLoader = createContextLoader(); ? //監(jiān)聽到WEB上下文初始化的時候執(zhí)行SPRING上下文contextLoader的初始化工作 this.contextLoader.initWebApplicationContext(event.getServletContext()); } ? /** * Create the ContextLoader to use. Can be overridden in subclasses. * @return the new ContextLoader */protected ContextLoader createContextLoader() {returnnew ContextLoader(); } ? /** * Return the ContextLoader used by this listener. */public ContextLoader getContextLoader() {return contextLoader; } ? /** * Close the root web application context. */publicvoid contextDestroyed(ServletContextEvent event) {if (this.contextLoader != null) { this.contextLoader.closeWebApplicationContext(event.getServletContext()); }} ? } |
看一下是怎么來初始化webapplicationContext的
==>contextLoader.initWebApplicationContext
1 | public WebApplicationContext initWebApplicationContext(ServletContext servletContext) throws IllegalStateException, BeansException { ? if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {thrownew IllegalStateException( "Cannot initialize context because there is already a root application context ? present - " +"check whether you have multiple ContextLoader* definitions in your web.xml!"); } ? long startTime = System.currentTimeMillis(); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } servletContext.log("Loading Spring root WebApplicationContext"); ? try{// Determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); ? // Store context in local instance variable, to guarantee that// it is available on ServletContext shutdown. ? //創(chuàng)建web上下文 this.context = createWebApplicationContext(servletContext, parent); servletContext.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ? if (logger.isInfoEnabled()) { logger.info("Using context class [" + this.context.getClass().getName() + "] for root WebApplicationContext"); }if (logger.isDebugEnabled()) { logger.debug("Published root WebApplicationContext [" + this.context + "] as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); }if (logger.isInfoEnabled()) {long elapsedTime = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ? ms");} ? return this.context; }catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; }catch (Error err) { logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; }} |
==>contextLoader.createWebApplicationContext(servletContext, parent);
==>contextLoader.determineContextClass(servletContext);
1 | protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException {//獲得需要實例化的CONTEXT類名,在web.xml中有設(shè)置,如果沒有設(shè)置,那么為空 String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); if (contextClassName != null) {try{return ClassUtils.forName(contextClassName); }catch (ClassNotFoundException ex) {thrownew ApplicationContextException( "Failed to load custom context class [" + contextClassName + "]", ex); }}//如果在spring web.xml中沒有設(shè)置context類位置,那么取得默認(rèn)contextelse{//取得defaultStrategies配置文件中的WebApplicationContext屬性 contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); try{return ClassUtils.forName(contextClassName); }catch (ClassNotFoundException ex) {thrownew ApplicationContextException( "Failed to load default context class [" + contextClassName + "]", ex); }}} |
SPRING上下文默認(rèn)的策略是甚么呢?
==>contextLoader.defaultStrategies
1 | privatestaticfinal Properties defaultStrategies; ? static{// Load default strategy implementations from properties file.// This is currently strictly internal and not meant to be customized// by application developers.try{//設(shè)置classpath為contextLoader同級目錄 ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); //加載該目錄下的所有properties文件 defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); }catch (IOException ex) {thrownew IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage()); }} |
找到同級目錄下的配置文件
==>ContextLoader.properties
1 | # Default WebApplicationContext implementation classfor ContextLoader. # Used as fallback when no explicit context implementation has been specified as context-param. # Not meant to be customized by application developers. ? #默認(rèn)的WebApplicationContext為org.springframework.web.context.support.XmlWebApplicationContext org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext |
==>org.springframework.web.context.support.XmlWebApplicationContext
1 | publicclass XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { ? /** Default config location for the root context */ ? //配置了默認(rèn)的spring配置文件publicstaticfinal String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; ? //配置文件默認(rèn)BUILD路徑publicstaticfinal String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; ? //配置文件默認(rèn)后綴名publicstaticfinal String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; ? /** * Loads the bean definitions via an XmlBeanDefinitionReader. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see #initBeanDefinitionReader * @see #loadBeanDefinitions *///獲得bean配置protectedvoid loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {//從BEAN工廠獲得一個XmlBeanDefinitionReader 來讀取SPRING配置文件 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); ? //設(shè)置beanDefinitionReader服務(wù)于當(dāng)前CONTEXT// resource loading environment. beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); ? // Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); //讀取配置文件 loadBeanDefinitions(beanDefinitionReader); } ? /** * Initialize the bean definition reader used for loading the bean * definitions of this context. Default implementation is empty. * <p>Can be overridden in subclasses, e.g. for turning off XML validation * or using a different XmlBeanDefinitionParser implementation. * @param beanDefinitionReader the bean definition reader used by this context * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setValidationMode * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass */protectedvoid initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {} ? /** * Load the bean definitions with the given XmlBeanDefinitionReader. * <p>The lifecycle of the bean factory is handled by the refreshBeanFactory method; * therefore this method is just supposed to load and/or register bean definitions. * <p>Delegates to a ResourcePatternResolver for resolving location patterns * into Resource instances. * @throws org.springframework.beans.BeansException in case of bean registration errors * @throws java.io.IOException if the required XML document isn't found * @see #refreshBeanFactory * @see #getConfigLocations * @see #getResources * @see #getResourcePatternResolver *///讀取配置文件protectedvoid loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) {for (int i = 0; i < configLocations.length; i++) { reader.loadBeanDefinitions(configLocations[i]); }}} ? /** * The default location for the root context is "/WEB-INF/applicationContext.xml", * and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet" * (like for a DispatcherServlet instance with the servlet-name "test"). *///獲得默認(rèn)的ConfigLocationsprotected String[] getDefaultConfigLocations() {if (getNamespace() != null) {returnnew String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + ? DEFAULT_CONFIG_LOCATION_SUFFIX}; }else{returnnew String[] {DEFAULT_CONFIG_LOCATION}; }} |
==>AbstractBeanDefinitionReader.loadBeanDefinitions()
1 | publicint loadBeanDefinitions(String location) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) {thrownew BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } ? if (resourceLoader instanceof ResourcePatternResolver) {// Resource pattern matching available.try{//根據(jù)配置文件讀取相應(yīng)配置 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); }return loadCount; }catch (IOException ex) {thrownew BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); }}else{// Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); }return loadCount; }} |
這個是其中一個ResourceLoader的實現(xiàn)
==>PathMatchingResourcePatternResolver.getResources(String locationPattern);
1 | public Resource[] getResources(String locationPattern) throws IOException { Assert.notNull(locationPattern, "Location pattern must not be null"); if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {// a class path resource (multiple resources for same name possible)if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {// a class path resource patternreturn findPathMatchingResources(locationPattern); }else{// all class path resources with the given namereturn findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length())); }}else{// Only look for a pattern after a prefix here// (to not get fooled by a pattern symbol in a strange prefix).int prefixEnd = locationPattern.indexOf(":") + 1; if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {// a file patternreturn findPathMatchingResources(locationPattern); }else{// a single resource with the given namereturnnew Resource[] {getResourceLoader().getResource(locationPattern)}; }}} |
==>PathMatchingResourcePatternResolver.findPathMatchingResources(String locationPattern);
1 | protected Resource[] findPathMatchingResources(String locationPattern) throws IOException { String rootDirPath = determineRootDir(locationPattern); String subPattern = locationPattern.substring(rootDirPath.length()); Resource[] rootDirResources = getResources(rootDirPath); //collectionFactory初始化一個set容量為16 Set result = CollectionFactory.createLinkedSetIfPossible(16); for (int i = 0; i < rootDirResources.length; i++) { Resource rootDirResource = rootDirResources[i]; if (isJarResource(rootDirResource)) { result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern)); }else{ result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern)); }}if (logger.isDebugEnabled()) { logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result); }return (Resource[]) result.toArray(new Resource[result.size()]); } |
前面說到有一個刷新WebApplicationContext的操作,但是XmlWebApplicationContext 并沒有實現(xiàn)refresh方法,而方法的實現(xiàn)寫在
AbstractRefreshableWebApplicationContext 中
==>AbstractRefreshableWebApplicationContext.refresh();
1 | publicvoid refresh() throws BeansException {if (ObjectUtils.isEmpty(getConfigLocations())) {//設(shè)置configLocations為默認(rèn)的getDefaultConfigLocations() setConfigLocations(getDefaultConfigLocations()); } super.refresh(); } |
==>AbstractApplicationContext.refresh();
1 | publicvoid refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) { this.startupTime = System.currentTimeMillis(); ? synchronized (this.activeMonitor) { this.active = true; } ? // Tell subclass to refresh the internal bean factory. refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); ? // Tell the internal bean factory to use the context's class loader. beanFactory.setBeanClassLoader(getClassLoader()); ? // Populate the bean factory with context-specific resource editors. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this)); ? // Configure the bean factory with context semantics. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); ? // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); ? // Invoke factory processors registered with the context instance.for (Iterator it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) { BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next(); factoryProcessor.postProcessBeanFactory(beanFactory); } ? if (logger.isInfoEnabled()) {if (getBeanDefinitionCount() == 0) { logger.info("No beans defined in application context [" + getDisplayName() + "]"); }else{ logger.info(getBeanDefinitionCount() + " beans defined in application context [" + ? getDisplayName() + "]"); }} ? try{// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(); ? // Register bean processors that intercept bean creation. registerBeanPostProcessors(); ? // Initialize message source for this context. initMessageSource(); ? // Initialize event multicaster for this context. initApplicationEventMulticaster(); ? // Initialize other special beans in specific context subclasses. onRefresh(); ? // Check for listener beans and register them. registerListeners(); ? // Instantiate singletons this late to allow them to access the message source. beanFactory.preInstantiateSingletons(); ? // Last step: publish corresponding event. publishEvent(new ContextRefreshedEvent(this)); } ? catch (BeansException ex) {// Destroy already created singletons to avoid dangling resources. beanFactory.destroySingletons(); throw ex; }}} |