基于Xml 的IOC 容器-将配置载入内存
生活随笔
收集整理的這篇文章主要介紹了
基于Xml 的IOC 容器-将配置载入内存
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
BeanDefinitionDocumentReader 接口通過registerBeanDefinitions() 方法調用其實現類DefaultBeanDefinitionDocumentReader 對Document 對象進行解析,解析的代碼如下:
//根據Spring DTD對Bean的定義規則解析Bean定義Document對象 @Override 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) {// Any nested <beans> elements will cause recursion in this method. In// order to propagate and preserve <beans> default-* attributes correctly,// keep track of the current (parent) delegate, which may be null. Create// the new (child) delegate with a reference to the parent for fallback purposes,// then ultimately reset this.delegate back to its original (parent) reference.// this behavior emulates a stack of delegates without actually necessitating one.//具體的解析過程由BeanDefinitionParserDelegate實現,//BeanDefinitionParserDelegate中定義了Spring Bean定義XML文件的各種元素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; } //創建BeanDefinitionParserDelegate,用于完成真正的解析過程 protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);//BeanDefinitionParserDelegate初始化Document根元素delegate.initDefaults(root, parentDelegate);return delegate; } //使用Spring的Bean規則從Document的根元素開始進行Bean定義的Document對象 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {//Bean定義的Document對象使用了Spring默認的XML命名空間if (delegate.isDefaultNamespace(root)) {//獲取Bean定義的Document對象根元素的所有子節點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)) {//使用Spring的Bean規則解析元素節點parseDefaultElement(ele, delegate);}else {//沒有使用Spring默認的XML命名空間,則使用用戶自定義的解//析規則解析元素節點delegate.parseCustomElement(ele);}}}}else {//Document的根節點沒有使用Spring默認的命名空間,則使用用戶自定義的//解析規則解析Document根節點delegate.parseCustomElement(root);} } //使用Spring的Bean規則解析Document元素節點 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);}//元素節點既不是導入元素,也不是別名元素,即普通的<Bean>元素,//按照Spring的Bean規則解析元素else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recursedoRegisterBeanDefinitions(ele);} }//解析<Import>導入元素,從給定的導入路徑加載Bean定義資源到Spring IoC容器中 protected void importBeanDefinitionResource(Element ele) {//獲取給定的導入元素的location屬性String location = ele.getAttribute(RESOURCE_ATTRIBUTE);//如果導入元素的location屬性值為空,則沒有導入任何資源,直接返回if (!StringUtils.hasText(location)) {getReaderContext().error("Resource location must not be empty", ele);return;}// Resolve system properties: e.g. "${user.dir}"//使用系統變量值解析location屬性值location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);Set<Resource> actualResources = new LinkedHashSet<>(4);// Discover whether the location is an absolute or relative URI//標識給定的導入元素的location是否是絕對路徑boolean absoluteLocation = false;try {absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();}catch (URISyntaxException ex) {// cannot convert to an URI, considering the location relative// unless it is the well-known Spring prefix "classpath*:"//給定的導入元素的location不是絕對路徑}// Absolute or relative?//給定的導入元素的location是絕對路徑if (absoluteLocation) {try {//使用資源讀入器加載給定路徑的Bean定義資源int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);if (logger.isDebugEnabled()) {logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");}}catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, ex);}}else {// No URL -> considering resource location as relative to the current file.//給定的導入元素的location是相對路徑try {int importCount;//將給定導入元素的location封裝為相對路徑資源Resource relativeResource = getReaderContext().getResource().createRelative(location);//封裝的相對路徑資源存在if (relativeResource.exists()) {//使用資源讀入器加載Bean定義資源importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);actualResources.add(relativeResource);}//封裝的相對路徑資源不存在else {//獲取Spring IOC容器資源讀入器的基本路徑String baseLocation = getReaderContext().getResource().getURL().toString();//根據Spring IOC容器資源讀入器的基本路徑加載給定導入路徑的資源importCount = getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources);}if (logger.isDebugEnabled()) {logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");}}catch (IOException ex) {getReaderContext().error("Failed to resolve current resource location", ele, ex);}catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",ele, ex);}}Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);//在解析完<Import>元素之后,發送容器導入其他資源處理完成事件getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); }/*** Process the given alias element, registering the alias with the registry.*/ //解析<Alias>別名元素,為Bean向Spring IoC容器注冊別名 protected void processAliasRegistration(Element ele) {//獲取<Alias>別名元素中name的屬性值String name = ele.getAttribute(NAME_ATTRIBUTE);//獲取<Alias>別名元素中alias的屬性值String alias = ele.getAttribute(ALIAS_ATTRIBUTE);boolean valid = true;//<alias>別名元素的name屬性值為空if (!StringUtils.hasText(name)) {getReaderContext().error("Name must not be empty", ele);valid = false;}//<alias>別名元素的alias屬性值為空if (!StringUtils.hasText(alias)) {getReaderContext().error("Alias must not be empty", ele);valid = false;}if (valid) {try {//向容器的資源讀入器注冊別名getReaderContext().getRegistry().registerAlias(name, alias);}catch (Exception ex) {getReaderContext().error("Failed to register alias '" + alias +"' for bean with name '" + name + "'", ele, ex);}//在解析完<Alias>元素之后,發送容器別名處理完成事件getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));} }/*** Process the given bean element, parsing the bean definition* and registering it with the registry.*/ //解析Bean定義資源Document對象的普通元素 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);// BeanDefinitionHolder是對BeanDefinition的封裝,即Bean定義的封裝類//對Document對象中<Bean>元素的解析由BeanDefinitionParserDelegate實現// 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);}// Send registration event.//在完成向Spring IOC容器注冊解析得到的Bean定義之后,發送注冊事件getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));} }通過上述Spring IOC 容器對載入的Bean 定義Document 解析可以看出,我們使用Spring 時,在Spring 配置文件中可以使用<import>元素來導入IOC 容器所需要的其他資源,Spring IOC 容器在解析時會首先將指定導入的資源加載進容器中。使用<ailas>別名時,Spring IOC 容器首先將別名元素所定義的別名注冊到容器中。
對于既不是<import>元素,又不是<alias>元素的元素,即Spring 配置文件中普通的<bean>元素的解析由BeanDefinitionParserDelegate 類的parseBeanDefinitionElement()方法來實現。這個解析的過程非常復雜,我們在mini 版本的時候,就用properties 文件代替了。
?
總結
以上是生活随笔為你收集整理的基于Xml 的IOC 容器-将配置载入内存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于Xml 的IOC 容器-分配解析策略
- 下一篇: 基于Xml 的IOC 容器-载入<bea