摘要:注冊上篇前言上文說到已經加載完畢,此時到了注冊的時候。創建新的子委托,該委托具有對父委托的引用,用于備份,然后最終將重置回其原始父引用。這種行為模擬了一堆委托,實際上并不需要委托。下篇中也會補充一些此文中關于注冊的細節內容。
BeanDefinition注冊-上篇 前言
上文說到Document已經加載完畢,此時到了Spring注冊BeanDefinition的時候。下面就一起來探究下Spring是怎么把Xml文檔注冊成BeanDefinition的吧。XmlBeanDefinitionReader.registerBeanDefinitions
registerBeanDefinitions方法
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //1. 創建BeanDefinitionDocumentReader BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //2. 設置documentReader的環境 documentReader.setEnvironment(getEnvironment()); //3. 查詢之前注冊的BeanDefinition的個數 int countBefore = getRegistry().getBeanDefinitionCount(); //4. 開始注冊BeanDefinition,注意里面創建了一個Reader上下文 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //5. 計算此次注冊的BeanDefinition的個數 return getRegistry().getBeanDefinitionCount() - countBefore; }創建BeanDefinitionDocumentReader
使用BeanUtils創建一個DefaultBeanDefinitionDocumentReader對象,用于解析成BeanDefinition對象
private Class> documentReaderClass = DefaultBeanDefinitionDocumentReader.class; //創建一個BeanDefinitionDocumentReader,此處使用的是DefaultBeanDefinitionDocumentReader protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { //利用反射機制,調用DefaultBeanDefinitionDocumentReader的構造函數,然后創建一個實例返回 return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); }createReaderContext(resource)
創建一個XmlReaderContext設置了命名空間解析器為DefaultNamespaceHandlerResolver
protected XmlReaderContext createReaderContext(Resource resource) { if (this.namespaceHandlerResolver == null) { this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver(); } return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, this.namespaceHandlerResolver); } protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() { return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader()); }DefaultNamespaceHandlerResolver
用來處理不同的命名空間的解析器,這些映射規則是配置在META-INF/spring.handlers文件中(見附圖)比如對于xmlns為http://www.springframework.org/schema/c的命名空間的處理器為org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers"; public DefaultNamespaceHandlerResolver(ClassLoader classLoader) { //設置類加載器和handlerMapping文件的位置 this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION); } public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) { Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null"); this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); this.handlerMappingsLocation = handlerMappingsLocation; }documentReader.registerBeanDefinitions
注冊beanDefinition
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); //獲取xml的根元素Element root = doc.getDocumentElement(); //注冊BeanDefinition doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { //獲取 profile 屬性值,我此處并沒有設置此屬性值,所以使用的是默認的 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); //如果有配置profile,則進入 if (StringUtils.hasText(profileSpec)) { //將profile放入一個數組中 //profile可以配置多個,中間以MULTI_VALUE_ATTRIBUTE_DELIMITERS(,或;)分隔 String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); //判斷環境是否接受此profile數組,如果環境中不允許就直接返回,不再進行注冊 //這就是為什么pfofile起作用的原因,和環境中的prfile不一致的配置,不會被Spring注冊到容器中 if (!getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } // Any nested elements will cause recursion in this method. In // order to propagate and preserve 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. //任何嵌套的 元素都將導致此方法中的遞歸。在為了正確地傳播和保存 缺省-*屬性,跟蹤當前(父)委托,它可能為空。創建新的(子)委托,該委托具有對父委托的引用,用于備份,然后最終將this.delegate重置回其原始(父)引用。這種行為模擬了一堆委托,實際上并不需要委托。這是直接翻譯的,可能比較書面語。 //口語化的描述是,因為在遞歸解析 中,為了正確的保持BeanDefinitionParserDelegate的引用關系,所以首先取出DefaultBeanDefinitionDocumentReader委托類暫存起來,然后創建一個新的委托類使用,最后再還原為之前的委托類。 //獲取此DefaultBeanDefinitionDocumentReader的解析委托類 BeanDefinitionParserDelegate parent = this.delegate; //利用現有的委托類(可能為null),創建一個新的委托類 this.delegate = createDelegate(this.readerContext, root, parent); //預處理root,當前是空實現,可自行擴展 preProcessXml(root); //真正的處理root,并注冊,詳細的見下一小節《parseBeanDefinitions》 parseBeanDefinitions(root, this.delegate); //后處理root,當前是空實現,可自行擴展 postProcessXml(root); this.delegate = parent; } //輔助方法分析 //創建一個新的委托類BeanDefinitionParserDelegate // protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { //目前createHelper返回的值都是null BeanDefinitionParserDelegate delegate = createHelper(readerContext, root, parentDelegate); //目前都會進入此判斷內 if (delegate == null) { //創建一個新的BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, getEnvironment()); //初始化,并通過readerContext分發一個開始注冊BeanDefinition的事件 delegate.initDefaults(root, parentDelegate); } return delegate; } //BeanDefinitionParserDelegate.initDefaults //默認的文檔BeanDefinition private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition(); public void initDefaults(Element root, BeanDefinitionParserDelegate parent) { //給defaults設置初始值 populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root); //分發一個defaultsRegistered事件 this.readerContext.fireDefaultsRegistered(this.defaults); } //讀取 中配置的屬性,并設置到defaults中 protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) { //設置 default-lazy-init , //值為default時,如果父節點不是null時,繼承父節的屬性值,否則為false String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { lazyInit = parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE; } defaults.setLazyInit(lazyInit); //設置 default-merge //值為default時,如果父節點不是null時,繼承父節的屬性值,否則為false String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE); if (DEFAULT_VALUE.equals(merge)) { merge = parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE; } defaults.setMerge(merge); //設置 default-autowire //值為default時,如果父節點不是null時,繼承父節的屬性值,否則為no String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE); if (DEFAULT_VALUE.equals(autowire)) { autowire = parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE; } defaults.setAutowire(autowire); // don"t fall back to parentDefaults for dependency-check as it"s no // longer supported in as of 3.0. Therefore, no nested // would ever need to fall back to it. //設置 default-dependency-check ,不用檢查父節點的值了 defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE)); //設置 default-autowire-candidates if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) { defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates()); } //設置 default-init-method if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) { defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setInitMethod(parentDefaults.getInitMethod()); } //設置 default-destroy-method if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) { defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setDestroyMethod(parentDefaults.getDestroyMethod()); } //設置此DocumentDefaultsDefinition的元數據源 defaults.setSource(this.readerContext.extractSource(root)); }
一個beans的圖示
parseBeanDefinitions委托模式石錘了!這里把root交給委托類delegate來處理,委托類delegate通過XmlReaderContext持有當前的XmlBeanDefinitionReader、命名空間解析器、原始資源、事件分發器等,又直接持有環境的引用,而XmlBeanDefinitionReader又有BeanDefinitionRegistry的引用,可以說集萬千寵愛于一身,所以能力非常強大。我不得不畫個圖來表示一下敬意!
這里解析是的
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //判斷root的xlmns是不是默認的名稱空間,即"http://www.springframework.org/schema/beans" //這里是的 if (delegate.isDefaultNamespace(root)) { //獲取全部子節點并遍歷 NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //如果節點是Element的話,這里主要是為了去除xml中無用的Text空節點 //比如:__a____ 是有5個Node的 //分別是: //1. 空白Text節點 //2. 節點 //3. 空白Text節點 //4. 節點 //5. 空白Text節點 if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { //解析有效節點,處理不同的標簽 import bean alias beans parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }parseDefaultElement
處理import 、alias、bean、beans 這四種標簽其中最復雜的就是 beans 標簽,他會導致程序遞歸到DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions方法,然后重復上面的所有步驟,有興趣的同學可以在< beans> 標簽中嵌入一個< beans>,來研究下Spring是如何處理遞歸的。我這里就不再深入討論了。
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 標簽 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } //處理 beans 標簽 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }processBeanDefinition
處理bean標簽,先解析默認命名空間中的屬性、和子標簽然后處理非默認命名空間的標簽
接著注冊BeanDefinition
最后發送一個BeanDefinition注冊事件
/** * Process the given bean element, parsing the bean definition * and registering it with the registry. */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //解析ele成BeanDefinition,并放入到BeanDefinitionHolder中 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); //如果bdHolder解析成功了就進行 if (bdHolder != null) { //解析非默認命名空間的屬性 //比如 http://www.springframework.org/schema/c 之類的標簽 //對應的解析器也是就在springs.handlers文件中配置的,比如*/c的是org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { //向IOC中注冊該BeanDefiniton!!! BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name "" + bdHolder.getBeanName() + """, ele, ex); } //最后發送一個BeanDefinition注冊事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
//調用parseBeanDefinitionElement public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } //實際將Element解析成Beanfinition的方法 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { //獲取id屬性 String id = ele.getAttribute(ID_ATTRIBUTE); //獲取name屬性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); //別名list Listaliases = new ArrayList (); //如果name屬性值不為空,按照 ,; 符號切分name,切分成一個name屬性,并放入到aliases中 //這里看出bean的定義,可以定義多個name值,只要通過逗號或者分號分隔即可。 if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } //把beanName設置成id, String beanName = id; //如果沒有配置id,就把name中配置的第一個值作為beanName if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML "id" specified - using "" + beanName + "" as bean name and " + aliases + " as aliases"); } } //如果傳入的containingBean為null,就檢驗beanName和aliases是不是已經被占用了, //占用了就拋出一個異常BeanDefinitionParsingException, //這里傳入的containingBean就是null,所以一定要經過里面檢查 if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } //把ele解析 beanDefinition, //其中此處的 beanDefinition的類型是GenericBeanDefinition AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { //如果beanName沒有的話,就使用BeanDefinitionReaderUtils.generateBeanName生成一個名字 if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML "id" nor "name" specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); // 用一個BeanDefinitionHolder ,把beanDefinition, beanName, aliasesArray封裝在一起然后返回 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
//檢查benaName、aliases是否被之前的bean占用 protected void checkNameUniqueness(String beanName, Listaliases, Element beanElement) { String foundName = null; //判斷beanName是否被使用 if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) { foundName = beanName; } //判斷是否aliases中有被占用的 if (foundName == null) { foundName = (String) CollectionUtils.findFirstMatch(this.usedNames, aliases); } //如果找到了占用,就拋出異常 if (foundName != null) { error("Bean name "" + foundName + "" is already used in this element", beanElement); } //如果沒有發現占用,就把beanName和aliaes全部放入到usedNames中 this.usedNames.add(beanName); this.usedNames.addAll(aliases); }
解析Bean中幾乎所有的屬性和一些配置的子標簽,一個示例Bean標簽的配置如圖
//Element解析成AbstractBeanDefinition public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { //把beanName壓入到棧parseState中 this.parseState.push(new BeanEntry(beanName)); String className = null; //獲取class屬性值,放入到className中 if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { //如果有parent屬性,設置到parent中 String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } //創建一個AbstractBeanDefinition,類型是GenericBeanDefinition AbstractBeanDefinition bd = createBeanDefinition(className, parent); //解析ele的屬性,并設置到BeanDefinition中 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); //如果此bean標簽有子標簽description的話,就把description中的值設置到bd中 //message bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //解析子標簽 // parseMetaElements(ele, bd); //解析子標簽,把配置的lookup-method放入到bd的methodOverrides中 // parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //解析 replaced-method 標簽 // parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析 構造函數標簽 // parseConstructorArgElements(ele, bd); //解析 屬性標簽 parsePropertyElements(ele, bd); //解析 標簽 parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }
//利用className和parentName創建一個BeanDefinition protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException { return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader()); } //BeanDefinitionReaderUtils.createBeanDefinition方法創建的BeanDefinition的類型是GenericBeanDefinition public static AbstractBeanDefinition createBeanDefinition( String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { //創建一個GenericBeanDefinition,設置ParentName, GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setParentName(parentName); //如果可以className和classLoader都有值的話,就把類Class加載出來,并設置到bd中 //如果classLoder為空的話,就只設置一個className if (className != null) { if (classLoader != null) { // bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { bd.setBeanClassName(className); } } return bd; }
幾乎設置了一個BeanDefinition需要的全部屬性
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { //解析spring2.x中的scope屬性 //解析Spring1.x中的singleton屬性 if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { // Spring 2.x "scope" attribute bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { error("Specify either "scope" or "singleton", not both", ele); } } else if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { // Spring 1.x "singleton" attribute bd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ? BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE); } else if (containingBean != null) { // Take default from containing bean in case of an inner bean definition. bd.setScope(containingBean.getScope()); } //設置bd的 abstract 屬性 if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } //設置bd的 lazy-init 屬性 String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); //設置bd的 autowire 屬性 String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); //設置bd的 dependency-check 屬性 String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE); bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); //設置bd的 depends-on 屬性 if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); } //設置bd的 autowire-candidate 屬性 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)); } //設置bd的 primary 屬性 if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); } //設置bd的 init-method 屬性 if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) { String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE); if (!"".equals(initMethodName)) { bd.setInitMethodName(initMethodName); } } else { if (this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } } //設置bd的 destroy-method 屬性 if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) { String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); if (!"".equals(destroyMethodName)) { bd.setDestroyMethodName(destroyMethodName); } } else { if (this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } } //設置bd的 factory-method 屬性 if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } //設置bd的 factory-bean 屬性 if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } return bd; }
BeanDefinition的繼承關系圖,可以看出GenericBeanDefinition的位置
寫的有點太多了,還有import標簽和 alias標簽的解析內容,我放置《BeanDefinition注冊-下篇》中一起講解。下篇中也會補充一些此文中關于注冊BeanDefintion的細節內容。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/75344.html
摘要:在上文中,我實現了一個很簡單的和容器。比如,我們所熟悉的就是在這里將切面邏輯織入相關中的。初始化的工作算是結束了,此時處于就緒狀態,等待外部程序的調用。其中動態代理只能代理實現了接口的對象,而動態代理則無此限制。 1. 背景 本文承接上文,來繼續說說 IOC 和 AOP 的仿寫。在上文中,我實現了一個很簡單的 IOC 和 AOP 容器。上文實現的 IOC 和 AOP 功能很單一,且 I...
Spring是一個開源的設計層面框架,解決了業務邏輯層和其他各層的松耦合問題,將面向接口的編程思想貫穿整個系統應用,同時它也是Java工作中必備技能之一... 前言 緊跟上篇 Spring解密 - XML解析 與 Bean注冊 ,我們接著往下分析源碼 解密 在 Spring 的 XML 配置里面有兩大類聲明,一個是默認的如 ,另一類就是自定義的如,兩種標簽的解析方式差異是非常大的。parseBe...
摘要:使用這個類庫中的類將會加載必要的工廠類和類。最終它并不會依賴于或來構建應用程序代碼。下面對各部分作用總結下。和無縫整合的機制和的認識在講如何無縫整合進之前,我們先認識下和這兩個接口的作用。附上上篇博文地址原理概括。 前言 本篇是繼上篇MyBatis原理概括延伸的,所以如果有小伙伴還沒看上篇博文的話,可以先去看下,也不會浪費大家太多的時間,因為本篇會結合到上篇敘述的相關內容。 好,切入正...
摘要:主要過程為調用自身的另一個有參構造器此處的即為本身此處的最終返回一個調用無參構造器創建出來的對象參數非空效驗保存創建一個用于注解解析器,后面會用到注冊需要用到的顧名思義,即為所處的環境,包括配置的讀取等。 零 前期準備 0 FBI WARNING 文章異常啰嗦且繞彎。 1 版本 spring版本 : spring 5.1.2.RELEASE IDE : idea 2018.3 2 Be...
摘要:在介紹自定義標簽解析前,先放一張圖幫助大家理解以下是如何從文件中解析并加載的。自定義標簽比如的值為根據獲取到的,獲取對應的對象。關于和加載先后順序的問題最后再集合一個小例子總結下吧當我們先解析了元素時,我們會遍歷所有已經注冊注冊表中。 今天我們來談談 Dubbo XML 配置相關內容。關于這部分內容我打算分為以下幾個部分進行介紹: Dubbo XML Spring 自定義 XML 標...
閱讀 2863·2021-10-14 09:42
閱讀 3182·2019-08-30 15:52
閱讀 3267·2019-08-30 14:02
閱讀 1113·2019-08-29 15:42
閱讀 538·2019-08-29 13:20
閱讀 1164·2019-08-29 12:24
閱讀 486·2019-08-26 10:20
閱讀 686·2019-08-23 18:31