关于sPRing容器的启动的主要的入口是AbstractapplicationContext的refresh()方法,这个方法非常重要;
[html] view plain copy public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // 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 all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } } 此方法中用obtainFreshBeanFactory方法间接的调用了子类(如AbstractRefreshableApplicationContext)实现的refreshBeanFctory()方法。[java] view plain copy /** * This implementation performs an actual refresh of this context's underlying * bean factory, shutting down the previous bean factory (if any) and * initializing a fresh bean factory for the next phase of the context's lifecycle. */ @Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } refreshBeanFctory()首先实例化一个BeanFactory(DefaultListableBeanFactory),然后调用抽象方法loadBeanDifinition(DefaultListableBeanFactory beanFactory),此方法由其子类实现,比如AbstractxmlApplicationContext、XmlWebApplicationContext等。[java] view plain copy protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); 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); } 在这个方法中,做了以下事情:1、首先创建了一个BeanDefinitionReader的实例(XmlBeanDefinitionReader), [java] view plain copy XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); 2、设置ResorceLoader为ApplicationContext实例本身(实际上是继承了DefaultResourceLoader,所以其实这里的ResourceLoader是DefaultResourceLoader),[java] view plain copy beanDefinitionReader.setResourceLoader(this); 3、调用loadBeanDefinitions(XmlBeanDefinitionReader reader)方法。 [java] view plain copy protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } 这个方法调用父类AbstractRefreshableConfigApplication的getConfigLocations方法,获取资源定义的路径,如果不是通过构造器传入的路径,则调用getDefaultConfigLocations的子类实现来获取资源定义路径(XmlWebApplicationContext)。然后调用BeanDefinitionReader的loadBeanDefinitions(String location)方法加载资源。[java] view plain copy public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL.只能加载一个绝对路径的URL资源 Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } } 在BeanDefinitionReader的loadBeanDefinitions的方法中,首先获取前面setter的ResourceLoader对象,调用ResourseLoader对象的getResources(location)方法(这个方法会根据location判断是否是classpathResource或者URL,如果都不是调用getResourceByPath(由子类FileSystemXmlApplicationContext或AbstractRefreshableWebApplicationContext等实现返回FileSystemResource或者ServletContextResource))获取具体的资源Resource。[java] view plain copy public Resource getResource(String location) { Assert.notNull(location, "Location must not be null"); if (location.startsWith(CLASSPATH_URL_PREFIX)) { return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader()); } else { try { // Try to parse the location as a URL... URL url = new URL(location); return new UrlResource(url); } catch (MalformedURLException ex) { // No URL -> resolve as resource path. return getResourceByPath(location); } } } FileSystemXmlApplication:[java] view plain copy protected Resource getResourceByPath(String path) { if (path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); AbstractRefreshableWebApplicationContext:[java] view plain copy protected Resource getResourceByPath(String path) { return new ServletContextResource(this.servletContext, path); }新闻热点
疑难解答