spring 入門 之執行機制
阿新 • • 發佈:2019-01-26
技術不太好,對spring在慢慢學習ing.寫的有錯誤還望指正.. spring的執行需要在web.xml加上spring的監聽, 配置spring的xml檔案路徑 <!-- 配置spring資源 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/applicationContext-*.xml</param-value> </context-param> 不寫上邊那個的話也行,代表預設路徑在java檔案有體現,下邊是配置監聽 <!-- 配置spring --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 在spring-web.release.jar中的ContextLoadListener這個類 public void contextInitialized(ServletContextEvent event) { contextLoader = createContextLoader(); if(contextLoader == null) contextLoader = this; //監聽web上下文初始化spring上下文 contextLoader.initWebApplicationContext(event.getServletContext()); } 然後追蹤到ContextLoad這個類 public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { Log logger; long startTime; if(servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) throw new IllegalStateException("Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!"); logger = LogFactory.getLog(org/springframework/web/context/ContextLoader); servletContext.log("Initializing Spring root WebApplicationContext"); if(logger.isInfoEnabled()) logger.info("Root WebApplicationContext: initialization started"); startTime = System.currentTimeMillis(); //建立web上下文 if(context == null) context = createWebApplicationContext(servletContext); if(context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)context; if(!cwac.isActive()) { if(cwac.getParent() == null) { ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } configureAndRefreshWebApplicationContext(cwac, servletContext); } } servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context); ClassLoader ccl = Thread.currentThread().getContextClassLoader(); if(ccl == org/springframework/web/context/ContextLoader.getClassLoader()) currentContext = context; else if(ccl != null) currentContextPerThread.put(ccl, context); if(logger.isDebugEnabled()) logger.debug((new StringBuilder()).append("Published root WebApplicationContext as ServletContext attribute with name [").append(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE).append("]").toString()); if(logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info((new StringBuilder()).append("Root WebApplicationContext: initialization completed in ").append(elapsedTime).append(" ms").toString()); } return context; RuntimeException ex; ex; logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; Error err; err; logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; } 然後追蹤到ContextLoad.createWebApplicationContext protected WebApplicationContext createWebApplicationContext(ServletContext sc) { //根據ServletContext來決定要例項化的webApplicationContext Class contextClass = determineContextClass(sc); if(!org/springframework/web/context/ConfigurableWebApplicationContext.isAssignableFrom(contextClass)) throw new ApplicationContextException((new StringBuilder()).append("Custom context class [").append(contextClass.getName()).append("] is not of type [").append(org/springframework/web/context/ConfigurableWebApplicationContext.getName()).append("]").toString()); else return (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass); } ==>ContextLoader.determineContextClass protected Class determineContextClass(ServletContext servletContext) { //獲得初始化的context類名,在web.xml中設定,沒有則為空 String contextClassName; contextClassName = servletContext.getInitParameter("contextClass"); if(contextClassName == null) break MISSING_BLOCK_LABEL_55; return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); ClassNotFoundException ex; ex; throw new ApplicationContextException((new StringBuilder()).append("Failed to load custom context class [").append(contextClassName).append("]").toString(), ex); //如果在web.xml中沒有設定context類的位置,那麼取預設的context //取得defaultStrategies配置中的WebApplocationContext屬性 contextClassName = defaultStrategies.getProperty(org/springframework/web/context/WebApplicationContext.getName()); return ClassUtils.forName(contextClassName, org/springframework/web/context/ContextLoader.getClassLoader()); ex; throw new ApplicationContextException((new StringBuilder()).append("Failed to load default context class [").append(contextClassName).append("]").toString(), ex); } spring上下文預設生成策略 ==>contextLoader.defaultStrategies static { try { //設定properties為ContextLoader同級目錄 ClassPathResource resource = new ClassPathResource("ContextLoader.properties", org/springframework/web/context/ContextLoader); //載入該目錄下的properties檔案 defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch(IOException ex) { throw new IllegalStateException((new StringBuilder()).append("Could not load 'ContextLoader.properties': ").append(ex.getMessage()).toString()); } } 找到同級目錄下的ContextLoader.properties配置檔案 # Default WebApplicationContext implementation class for ContextLoader. # Used as fallback when no explicit context implementation has been specified as context-param. # Not meant to be customized by application developers. #預設的webApplicationContext為org.springframework.web.context.support.XmlWebApplicationContext org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext 找到此包下的XmlWebApplicationContext檔案 public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { public XmlWebApplicationContext() { } //獲取bean配置 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { //從bean工廠獲取一個XmlBeanDefinitionReader來讀取Spring配置檔案 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setEnvironment(getEnvironment()); //設定beanDefinitionReader服務當前CONTEXT beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); initBeanDefinitionReader(beanDefinitionReader); //讀取配置檔案 loadBeanDefinitions(beanDefinitionReader); } protected void initBeanDefinitionReader(XmlBeanDefinitionReader xmlbeandefinitionreader) { } //讀取配置檔案 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { String configLocations[] = getConfigLocations(); if(configLocations != null) { String arr$[] = configLocations; int len$ = arr$.length; for(int i$ = 0; i$ < len$; i$++) { String configLocation = arr$[i$]; reader.loadBeanDefinitions(configLocation); } } } //獲得預設的Configlocation protected String[] getDefaultConfigLocations() { if(getNamespace() != null) return (new String[] { (new StringBuilder()).append("/WEB-INF/").append(getNamespace()).append(".xml").toString() }); else return (new String[] { "/WEB-INF/applicationContext.xml" }); } //配置了預設的spring配置檔案 public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; //配置檔案預設的build路徑 public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; //配置檔案預設字尾名 public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; } 然後loadBeanDefinitions這個方法在spring-bean.release.jar中的AbstractBeanDefinitionReader中 public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { return loadBeanDefinitions(location, null); } public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader; resourceLoader = getResourceLoader(); if(resourceLoader == null) throw new BeanDefinitionStoreException((new StringBuilder()).append("Cannot import bean definitions from location [").append(location).append("]: no ResourceLoader available").toString()); if(!(resourceLoader instanceof ResourcePatternResolver)) break MISSING_BLOCK_LABEL_207; int loadCount; //根據配置檔案讀取相應位置 Resource resources[] = ((ResourcePatternResolver)resourceLoader).getResources(location); loadCount = loadBeanDefinitions(resources); if(actualResources != null) { Resource arr$[] = resources; int len$ = arr$.length; for(int i$ = 0; i$ < len$; i$++) { Resource resource = arr$[i$]; actualResources.add(resource); } } if(logger.isDebugEnabled()) logger.debug((new StringBuilder()).append("Loaded ").append(loadCount).append(" bean definitions from location pattern [").append(location).append("]").toString()); return loadCount; IOException ex; ex; throw new BeanDefinitionStoreException((new StringBuilder()).append("Could not resolve bean definition resource pattern [").append(location).append("]").toString(), ex); Resource resource = resourceLoader.getResource(location); loadCount = loadBeanDefinitions(resource); if(actualResources != null) actualResources.add(resource); if(logger.isDebugEnabled()) logger.debug((new StringBuilder()).append("Loaded ").append(loadCount).append(" bean definitions from location [").append(location).append("]").toString()); return loadCount; } 分析一個ResourceLoader的實現在spring-core-3.2.1.RELEASE.jar中的 org.springframework.core.io.support包裡 有一個PathMatchingResourcePatternResolver實現其介面 public Resource[] getResources(String locationPattern) throws IOException { Assert.notNull(locationPattern, "Location pattern must not be null"); if(locationPattern.startsWith("classpath*:")) if(getPathMatcher().isPattern(locationPattern.substring("classpath*:".length()))) return findPathMatchingResources(locationPattern); else return findAllClassPathResources(locationPattern.substring("classpath*:".length())); int prefixEnd = locationPattern.indexOf(":") + 1; if(getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) return findPathMatchingResources(locationPattern); else return (new Resource[] { getResourceLoader().getResource(locationPattern) }); } 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 = new LinkedHashSet(16); Resource arr$[] = rootDirResources; int len$ = arr$.length; for(int i$ = 0; i$ < len$; i$++) { Resource rootDirResource = arr$[i$]; rootDirResource = resolveRootDirResource(rootDirResource); if(isJarResource(rootDirResource)) { result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern)); continue; } if(rootDirResource.getURL().getProtocol().startsWith("vfs")) result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher())); else result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern)); } if(logger.isDebugEnabled()) logger.debug((new StringBuilder()).append("Resolved location pattern [").append(locationPattern).append("] to resources ").append(result).toString()); return (Resource[])result.toArray(new Resource[result.size()]); }