相关代码提交记录:https://github.com/linweiwang/spring-framework-5.3.33
IoC 容器三种启动方式 XML
JavaSE:
1 2 ApplicationContext context = new ClassPathXmlApplicationContext ("beans.xml" )ApplicationContext context = new FileSystemXmlApplicationContext ("C:/beans.xml" )
JavaWeb
1 通过 web.xml 配置 ContextLoaderListener,指定 Spring 配置文件。
XML+注解
因为有 XML ,所以和纯 XML 启动方式一样
注解
JavaSE
1 ApplicationContext context = new AnnotationConfigApplicationContext (SpringConfig.class)
JavaWeb
1 通过 web.xml 配置 ContextLoaderListener,指定 Spring 配置文件。
BeanFactory 是 Spring 框架中 IoC 容器的顶层接⼝,它只是⽤来定义⼀些基础功能,定义⼀些基础规范,⽽ ApplicationContext 是它的⼀个⼦接⼝,所以 ApplicationContext 是具备 BeanFactory 提供的全部功能力的。 通常,我们称 BeanFactory 为 SpringIOC 的基础容器,ApplicationContext 是容器的⾼级接⼝,⽐ BeanFactory 要拥有更多的功能,⽐如说国际化⽀持和资源访问(XML、Java 配置类)等等。
下面以纯 XML 依赖原有 spring-research 来跟踪源码。
IoC 容器初始化主体流程 分析 new ClassPathXmlApplicationContext("spring-config.xml");
ClassPathXmlApplicationContext.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public ClassPathXmlApplicationContext (String configLocation) throws BeansException { this (new String [] {configLocation}, true , null ); } public ClassPathXmlApplicationContext ( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super (parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
进入 refresh() 方法,在父类 AbstractApplicationContext 中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 @Override public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { StartupStep contextRefresh = this .applicationStartup.start("spring.context.refresh" ); prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this .applicationStartup.start("spring.context.beans.post-process" ); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); beanPostProcess.end(); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); contextRefresh.end(); } } }
整体流程如下:
1 刷新前的预处理: prepareRefresh(); 主要是一些准备工作设置其启动日期和活动标志以及执行一些属性的初始化。 2 初始化 BeanFactory: obtainFreshBeanFactory();
如果有旧的 BeanFactory 就删除并创建新的 BeanFactory
解析所有的 Spring 配置文件,将配置文件中定义的 bean 封装成 BeanDefinition,加载到BeanFactory 中(这里只注册,不会进行 Bean 的实例化)
3 BeanFactory 预准备工作:prepareBeanFactory(beanFactory); 配置 BeanFactory 的标准上下文特征,例如上下文的 ClassLoader、后置处理器等。
4 BeanFactory 准备工作完成后的后置处理,留给子类实现:postProcessBeanFactory(beanFactory); 空方法,如果子类需要,自己去实现
5 调用 Bean 工厂后置处理器:invokeBeanFactoryPostProcessors(beanFactory);
实例化和调用所有BeanFactoryPostProcessor,完成类的扫描、解析和注册。 BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。
6 注册 BeanPostProcesso:registerBeanPostProcessors(beanFactory); 所有实现了 BeanPostProcessor 接口的类注册到 BeanFactory 中。
7 初始化 MessageSource 组件:initMessageSource(); 初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
8 初始化事件派发器:initApplicationEventMulticaster(); 初始化应用的事件派发/广播器 ApplicationEventMulticaster。
9 初始化其他特殊的 Bean:onRefresh(); 空方法,模板设计模式;子类重写该方法并在容器刷新的时候自定义逻辑。 例:SpringBoot 在 onRefresh() 完成内置 Tomcat 的创建及启动
10 注册应用监听器:registerListeners(); 向事件分发器注册硬编码设置的 ApplicationListener,向事件分发器注册一个 IoC 中的事件监听器(并不实例化)
11 初始化创建非懒加载的单例 Bean:finishBeanFactoryInitialization(beanFactory); 初始化创建非懒加载的单例 Bean、填充属性、调用初始化方法( afterPropertiesSet,init-method 等)、调用 BeanPostProcessor 后置处理器,是整个 Spring IoC 核心中的核心。
12 完成 context 刷新:finishRefresh(); 完成 context 刷新,调用 LifecycleProcessor 的 onRefresh 方法并发布 ContextRefreshedEvent
获取 BeanFactory 子流程 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
AbstractApplicationContext.java
1 2 3 4 5 6 protected ConfigurableListableBeanFactory obtainFreshBeanFactory () { refreshBeanFactory(); return getBeanFactory(); }
AbstractRefreshableApplicationContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Override protected final void refreshBeanFactory () throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); this .beanFactory = beanFactory; } catch (IOException ex) { throw new ApplicationContextException ("I/O error parsing bean definition source for " + getDisplayName(), ex); } } @Override public final ConfigurableListableBeanFactory getBeanFactory () { DefaultListableBeanFactory beanFactory = this .beanFactory; if (beanFactory == null ) { throw new IllegalStateException ("BeanFactory not initialized or already closed - " + "call 'refresh' before accessing beans via the ApplicationContext" ); } return beanFactory; }
BeanDefinition 加载解析及注册子流程 继续分析 AbstractRefreshableApplicationContext#refreshBeanFactory 中的 loadBeanDefinitions 的实现方法在 AbstractXmlApplicationContext#loadBeanDefinitions 中(若是注解在 AnnotationConfigWebApplicationContext)
AbstractXmlApplicationContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Override protected void loadBeanDefinitions (DefaultListableBeanFactory beanFactory) throws BeansException, IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader (beanFactory); beanDefinitionReader.setEnvironment(getEnvironment()); beanDefinitionReader.setResourceLoader(this ); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver (this )); initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } 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); } }
reader.loadBeanDefinitions(configLocations); 中调用了 AbstractBeanDefinitionReader#loadBeanDefinitions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 @Override public int loadBeanDefinitions (String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null" ); int count = 0 ; for (String location : locations) { count += loadBeanDefinitions(location); } return count; } @Override public int loadBeanDefinitions (String location) throws BeanDefinitionStoreException { return loadBeanDefinitions(location, null ); } public int loadBeanDefinitions (String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null ) { throw new BeanDefinitionStoreException ( "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available" ); } if (resourceLoader instanceof ResourcePatternResolver) { try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int count = loadBeanDefinitions(resources); if (actualResources != null ) { Collections.addAll(actualResources, resources); } if (logger.isTraceEnabled()) { logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]" ); } return count; } catch (IOException ex) { throw new BeanDefinitionStoreException ( "Could not resolve bean definition resource pattern [" + location + "]" , ex); } } else { Resource resource = resourceLoader.getResource(location); int count = loadBeanDefinitions(resource); if (actualResources != null ) { actualResources.add(resource); } if (logger.isTraceEnabled()) { logger.trace("Loaded " + count + " bean definitions from location [" + location + "]" ); } return count; } } @Override public int loadBeanDefinitions (Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null" ); int count = 0 ; for (Resource resource : resources) { count += loadBeanDefinitions(resource); } return count; } @Override public int loadBeanDefinitions (Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null" ); int count = 0 ; for (Resource resource : resources) { count += loadBeanDefinitions(resource); } return count; }
loadBeanDefinitions(resource); 调用了 XmlBeanDefinitionReader#loadBeanDefinitions 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 @Override public int loadBeanDefinitions (Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource (resource)); } public int loadBeanDefinitions (EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null" ); if (logger.isTraceEnabled()) { logger.trace("Loading XML bean definitions from " + encodedResource); } Set<EncodedResource> currentResources = this .resourcesCurrentlyBeingLoaded.get(); if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException ( "Detected cyclic loading of " + encodedResource + " - check your import definitions!" ); } try (InputStream inputStream = encodedResource.getResource().getInputStream()) { InputSource inputSource = new InputSource (inputStream); if (encodedResource.getEncoding() != null ) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } catch (IOException ex) { throw new BeanDefinitionStoreException ( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this .resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions (InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException (resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid" , ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException (resource.getDescription(), "XML document from " + resource + " is invalid" , ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException (resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException (resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException (resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } } public int registerBeanDefinitions (Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 会进入 DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 @Override public void registerBeanDefinitions (Document doc, XmlReaderContext readerContext) { this .readerContext = readerContext; doRegisterBeanDefinitions(doc.getDocumentElement()); } protected void doRegisterBeanDefinitions (Element root) { BeanDefinitionParserDelegate parent = this .delegate; this .delegate = createDelegate(getReaderContext(), root, parent); if (this .delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isDebugEnabled()) { logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return ; } } } preProcessXml(root); parseBeanDefinitions(root, this .delegate); postProcessXml(root); this .delegate = parent; } protected void parseBeanDefinitions (Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0 ; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } private void parseDefaultElement (Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { doRegisterBeanDefinitions(ele); } } protected void processBeanDefinition (Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'" , ele, ex); } getReaderContext().fireComponentRegistered(new BeanComponentDefinition (bdHolder)); } }
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 调用了 BeanDefinitionReaderUtils#registerBeanDefinition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static void registerBeanDefinition ( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); String[] aliases = definitionHolder.getAliases(); if (aliases != null ) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); 调用了 DefaultListableBeanFactory#registerBeanDefinition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 @Override public void registerBeanDefinition (String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty" ); Assert.notNull(beanDefinition, "BeanDefinition must not be null" ); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException (beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed" , ex); } } BeanDefinition existingDefinition = this .beanDefinitionMap.get(beanName); if (existingDefinition != null ) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException (beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]" ); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]" ); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]" ); } } this .beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { synchronized (this .beanDefinitionMap) { this .beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList <>(this .beanDefinitionNames.size() + 1 ); updatedDefinitions.addAll(this .beanDefinitionNames); updatedDefinitions.add(beanName); this .beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); } } else { this .beanDefinitionMap.put(beanName, beanDefinition); this .beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this .frozenBeanDefinitionNames = null ; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } else if (isConfigurationFrozen()) { clearByTypeCache(); } }
整体调用链如下
1 2 3 4 5 6 7 8 9 10 11 12 13 AbstractRefreshableApplicationContext#refreshBeanFactory AbstractXmlApplicationContext#loadBeanDefinitions AbstractBeanDefinitionReader#loadBeanDefinitions // 加载 BeanDefinition XmlBeanDefinitionReader#loadBeanDefinitions XmlBeanDefinitionReader#doLoadBeanDefinitions // 读取 XML 为 Document XmlBeanDefinitionReader#registerBeanDefinitions // 真正开始注册 DefaultBeanDefinitionDocumentReader#registerBeanDefinitions DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions DefaultBeanDefinitionDocumentReader#parseBeanDefinitions DefaultBeanDefinitionDocumentReader#parseDefaultElement DefaultBeanDefinitionDocumentReader#processBeanDefinition BeanDefinitionReaderUtils#registerBeanDefinition DefaultListableBeanFactory#registerBeanDefinition