Spring Ioc 的源碼初識
剛學習Spring的時候,印象最深的就是 DispatcherServlet,所謂的中央調度器,我也嘗試從這個萬能膠這裏找到入口
configureAndRefreshWebApplicationContext()方法,應該就是IOC容器初始化的真正入口
我開始手寫測試用例(xml配置的bean實例),ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("xxx.xml");
通過跟蹤代碼和debug的方式,找到了大概的初始化流程
ClassPathXmlApplicationContext 的構造方法
public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); }
AbstractApplicationContext類
接著--->>>
接著--->>>AbstractXmlApplicationContext
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { //創建XmlBeanDefinitionReader XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setEnvironment(this.getEnvironment()); //容器本身也是一個資源加載器 beanDefinitionReader.setResourceLoader(this); //為Bean讀取器設置SAX xml解析器 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //當Bean讀取器讀取Bean定義的Xml資源文件時,啟用Xml的校驗機制 initBeanDefinitionReader(beanDefinitionReader); //Bean讀取器真正實現加載的方法 loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //獲取Bean定義資源的定位 Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } //如果子類中獲取的Bean定義資源定位為空,則獲取FileSystemXmlApplicationContext構造方法中setConfigLocations方法設置的資源 String[] configLocations = getConfigLocations(); if (configLocations != null) { //Xml Bean讀取器調用其父類AbstractBeanDefinitionReader讀取定位 reader.loadBeanDefinitions(configLocations); } }
接著--->>>AbstractBeanDefinitionReader
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int counter = 0; for (String location : locations) { counter += loadBeanDefinitions(location); } return counter; }
接著--->>>
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { return loadBeanDefinitions(location, null); }
接著--->>>
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { //獲取在IoC容器初始化過程中設置的資源加載器 ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { try { //加載多個指定位置的Bean定義資源文件 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); //委派調用其子類XmlBeanDefinitionReader的方法,實現加載功能 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 { 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; } }
接著--->>>
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { counter += loadBeanDefinitions(resource); } return counter; }
接著--->>>XmlBeanDefinitionReader
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { //將讀入的XML資源進行特殊編碼處理 return loadBeanDefinitions(new EncodedResource(resource)); }
接著--->>>
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) {logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { //將資源文件轉為InputStream的IO流 InputStream inputStream = encodedResource.getResource().getInputStream(); try { //從InputStream中得到XML的解析源 InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //這裏是具體的讀取過程 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally {inputStream.close();} }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 { //將XML文件轉換為DOM對象,解析過程由documentLoader實現 Document doc = doLoadDocument(inputSource, resource); //這裏是啟動對Bean定義解析的詳細過程,該解析過程會用到Spring的Bean配置規則 return registerBeanDefinitions(doc, resource); } catch (Exception ex) { throw ex; }}
接著--->>>
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //獲取BeanDefinitionDocumentReader BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //獲得容器中註冊的Bean數量 int countBefore = getRegistry().getBeanDefinitionCount(); //具體的解析實現過程實現類DefaultBeanDefinitionDocumentReader完成 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //統計解析的Bean數量 return getRegistry().getBeanDefinitionCount() - countBefore; }
接著--->>>DefaultBeanDefinitionDocumentReader
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { //獲得XML描述符 this.readerContext = readerContext; logger.debug("Loading bean definitions"); //獲得Document的根元素 Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
接著--->>>
protected void doRegisterBeanDefinitions(Element root) { //具體的解析過程由BeanDefinitionParserDelegate實現, 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.isInfoEnabled()) {logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); }return;}}} //在解析Bean定義之前,進行自定義的解析,增強解析過程的可擴展性 preProcessXml(root); //從Document的根元素開始進行Bean定義的Document對象 parseBeanDefinitions(root, this.delegate); //在解析Bean定義之後,進行自定義的解析,增加解析過程的可擴展性 postProcessXml(root); this.delegate = parent; }
接著--->>>
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //Bean定義的Document對象使用了Spring默認的XML命名空間 if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //獲得Document節點是XML元素節點 if (node instanceof Element) { Element ele = (Element) node; //Bean定義的Document的元素節點使用的是Spring默認的XML命名空間 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
接著--->>>
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //如果元素節點是<Import>導入元素,進行導入解析 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } //如果元素節點是<Alias>別名元素,進行別名解析 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } //按照Spring的Bean規則解析元素 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
接著--->>>
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); // BeanDefinitionHolder是對BeanDefinition的封裝,即Bean定義的封裝類 // BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //向Spring IOC容器註冊解析得到的Bean定義,這是Bean定義向IOC容器註冊的入口 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name ‘" +bdHolder.getBeanName() + "‘", ele, ex); } //在完成向Spring IOC容器註冊解析得到的Bean定義之後,發送註冊事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
接著--->>>BeanDefinitionReaderUtils
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { //獲取解析的BeanDefinition的名稱 String beanName = definitionHolder.getBeanName(); //向IOC容器註冊BeanDefinition registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); //如果解析的BeanDefinition有別名,向容器為其註冊別名 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
Spring Ioc 的源碼初識