关于spring容器的启动的主要的入口是AbstractApplicationContext的refresh()方法,这个方法非常重要;
- 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()方法。
- /**
- * 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等。
- 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),
- XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
2、设置ResorceLoader为ApplicationContext实例本身(实际上是继承了DefaultResourceLoader,所以其实这里的ResourceLoader是
DefaultResourceLoader),
- beanDefinitionReader.setResourceLoader(this);
3、调用loadBeanDefinitions(XmlBeanDefinitionReader reader)方法。
- 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)方法加载资源。
- 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。
- 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:
- protected Resource getResourceByPath(String path) {
- if (path != null && path.startsWith("/")) {
- path = path.substring(1);
- }
- return new FileSystemResource(path);
AbstractRefreshableWebApplicationContext:
- protected Resource getResourceByPath(String path) {
- return new ServletContextResource(this.servletContext, path);
- }