摘要:前言繼續前一章,接下來解析標簽的的屬性信息及的注冊。不過只不過是一個子類的實現,而大部分屬性都是保存到了中去了。也就是函數中的代碼的解析了。通過注冊對于的注冊,或許很多人認為的方式就是將直接放入中就好了,使用作為。
前言:繼續前一章,接下來解析Bean標簽的的屬性信息及bean的注冊。 1. 解析當前bean標簽的內容
當我們創建了bean信息的承載實例之后, 便可以進行bean信息的各種屬性的解析了, 首先我們進入parseBeanDefinitionAttributes方法,parseBeanDefinitionAttributes方法是對element所有元素屬性進行解析:
/**
* Apply the attributes of the given bean element to the given bean * definition. * @param ele bean declaration element * @param beanName bean name * @param containingBean containing bean definition * @return a bean definition initialized according to the bean element attributes */ public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) { if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { error("Old 1.x "singleton" attribute in use - upgrade to "scope" declaration", ele); } else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); } else if (containingBean != null) { // Take default from containing bean in case of an inner bean definition. bd.setScope(containingBean.getScope()); } if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); } String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) { String candidatePattern = this.defaults.getAutowireCandidates(); if (candidatePattern != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } else { bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); } if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); } if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) { String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE); bd.setInitMethodName(initMethodName); } else if (this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) { String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); bd.setDestroyMethodName(destroyMethodName); } else if (this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } return bd; }
通過以上代碼我們可以發現, 在1.0版本會有一個singleton 不過呢, 這個很快就被取代掉了, 使用的話會提示錯誤信息, 在新的版本里, 我們使用了scpoe=“singleton” 作為一個新的使用方式, 我們都知道在spring中,所創建的bean 都被認為默認認為是單例的,并且通過scope這個關鍵字,即scope="singleton"。另外scope還有prototype、request、session、global session作用域。scope="prototype"多例。 scope就是一個作用域,如果有不太理解的話,可以參照一下:Spring scope作用域詳解。在這里只是看了一下scope標簽的解析, 那么肯定還會有很多的屬性, 我們用或者沒有用過, 但是就不做講解了, 我們知道spring是如何去做的就好了。
2. 解析bean中的元數據, meta中的內容例如:
通常我們通過配置文件使用spring的時候, 我們會用到meta這個標簽,這個標簽中門會配置上, key, 和value這兩個屬性,
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) { NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) { Element metaElement = (Element) node; String key = metaElement.getAttribute(KEY_ATTRIBUTE); String value = metaElement.getAttribute(VALUE_ATTRIBUTE); BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value); attribute.setSource(extractSource(metaElement)); attributeAccessor.addMetadataAttribute(attribute); } } }
通過代碼, 我們可以發現, spring通過解析得到的Element樹對象去得到子節點, 然后便利子節點, 并且取得meta元素的key值和value的知值,然后將其存儲在attributeAccessor中。由此推測, 其他的子集標簽也會是通過這種方式去加載, 并且這也符合我們的預期。
3. 重提AbstractBeanDefinition屬性至此我們便完成了對xml文檔到GenericBenaDefinition的轉換, 也就是說我們將xml里面所有的配置都保存到了一個java實例中去了。不過GenericBenaDefinition只不過是一個子類的實現, 而大部分屬性都是保存到了AbstractBeanDefinition中去了。
當打開AbstractBeanDefinition這個類我們可以發現, 幾乎所有同bean配置的屬性都已經在這個類中進行了定義:
public static final String SCOPE_DEFAULT = "";
/** * Constant that indicates no autowiring at all. * @see #setAutowireMode */ public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO; /** * Constant that indicates autowiring bean properties by name. * @see #setAutowireMode */ public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; /** * Constant that indicates autowiring bean properties by type. * @see #setAutowireMode */ public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE; /** * Constant that indicates autowiring a constructor. * @see #setAutowireMode */ public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR; /** * Constant that indicates determining an appropriate autowire strategy * through introspection of the bean class. * @see #setAutowireMode * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies, * use annotation-based autowiring for clearer demarcation of autowiring needs. */ @Deprecated public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
這里就不進行一一列舉了。
4.注冊解析的BeanDefinition對于配置文件的解析已經完成了,我們得到了整個配置的內容, 接下來呢Spring做的事就是對注冊了。也就是processBeanDeefinition函數中的registerBeanDefinition(bdHolder, getReaderContext(),getRegistry())代碼的解析了。
/** * Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed */ public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
從上面的代碼可以看出, 解析的beanDefinition都被注冊到BeanDefinitionRegistry類型的實例registry, 而對于beanDefinition的注冊分成了兩部分:通過beanName的注冊以及通過別名注冊。
通過beanName 注冊BeanDefinition
對于beanDefinition的注冊, 或許很多人認為的方式就是將beanDefinition直接放入map中就好了, 使用beanName作為key。確實,Spring就是這么做的, 只不過除此之外, 它還做了點別的事情。
@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()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE 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()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); ListupdatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
通過上面的代碼可以發現, Spring確實將beanName放到了一個名字叫做beanDefinitionMap這樣的一個map之中,這個map的類型是線程安全的ConcurrentHashMap, 而在這之前,只不過是做了一些驗證。而對于通過別名進行注冊的BeanDefinition, 代碼是這樣的:
@Override
public void registerAlias(String name, String alias) { Assert.hasText(name, ""name" must not be empty"); Assert.hasText(alias, ""alias" must not be empty"); synchronized (this.aliasMap) { if (alias.equals(name)) { this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition "" + alias + "" ignored since it points to same name"); } } else { String registeredName = this.aliasMap.get(alias); if (registeredName != null) { if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot define alias "" + alias + "" for name "" + name + "": It is already registered for name "" + registeredName + ""."); } if (logger.isDebugEnabled()) { logger.debug("Overriding alias "" + alias + "" definition for registered name "" + registeredName + "" with new target name "" + name + """); } } checkForAliasCircle(name, alias); this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition "" + alias + "" registered for name "" + name + """); } } } }
通過以上的代碼我們可以發現, 在得知是注冊alias的步驟中, 這里也會有一個名字為aliasMap的map用來存儲注冊的別名,我這里有個疑惑, 就是怎么才能通過別名與原有的beanName進行映射呢? 如果都注冊了, 那么將以哪個為準呢? 留給以后再看,留給評論。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73652.html
摘要:本文是容器源碼分析系列文章的第一篇文章,將會著重介紹的一些使用方法和特性,為后續的源碼分析文章做鋪墊。我們可以通過這兩個別名獲取到這個實例,比如下面的測試代碼測試結果如下本小節,我們來了解一下這個特性。 1. 簡介 Spring 是一個輕量級的企業級應用開發框架,于 2004 年由 Rod Johnson 發布了 1.0 版本。經過十幾年的迭代,現在的 Spring 框架已經非常成熟了...
摘要:對于開發者來說,無疑是最常用也是最基礎的框架之一。概念上的東西還是要提一嘴的用容器來管理。和是容器的兩種表現形式。定義了簡單容器的基本功能。抽象出一個資源類來表示資源調用了忽略指定接口的自動裝配功能委托解析資源。 對于Java開發者來說,Spring無疑是最常用也是最基礎的框架之一。(此處省略1w字吹Spring)。相信很多同行跟我一樣,只是停留在會用的階段,比如用@Component...
摘要:進一步解析其他所有屬性并統一封裝至類型的實例中。是一個接口,在中存在三種實現以及。通過將配置文件中配置信息轉換為容器的內部表示,并將這些注冊到中。容器的就像是配置信息的內存數據庫,主要是以的形式保存。而代碼的作用就是實現此功能。 前言:繼續前一章。 一、porfile 屬性的使用 如果你使用過SpringBoot, 你一定會知道porfile配置所帶來的方便, 通過配置開發環境還是生產...
摘要:入門篇學習總結時間年月日星期三說明本文部分內容均來自慕課網。主要的功能是日志記錄,性能統計,安全控制,事務處理,異常處理等等。 《Spring入門篇》學習總結 時間:2017年1月18日星期三說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學示例源碼:https://github.com/zccodere/s...個人學習源碼:https://git...
摘要:從使用到原理學習線程池關于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實現在軟件開發中,分散于應用中多出的功能被稱為橫切關注點如事務安全緩存等。 Java 程序媛手把手教你設計模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經風雨慢慢變老,回首走過的點點滴滴,依然清楚的記得當初愛情萌芽的模樣…… Java 進階面試問題列表 -...
閱讀 3070·2021-11-22 13:54
閱讀 834·2021-11-04 16:08
閱讀 4464·2021-10-11 11:09
閱讀 3597·2021-09-22 16:05
閱讀 910·2019-08-30 15:54
閱讀 387·2019-08-30 15:44
閱讀 594·2019-08-30 14:05
閱讀 1014·2019-08-30 12:46