【spring源碼分析】IOC容器初始化(三)

前言:在【spring源碼分析】IOC容器初始化(二)中已經獲得了XML配置文件的Document實例,下面分析bean的註冊過程。html


XmlBeanDefinitionReader#registerBeanDefinitions(Document doc, Resource resource)

 1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
 2         // #1.建立BeanDefinitionDocumentReader對象
 3         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
 4         // #2.獲取已註冊過的BeanDefinition對象個數
 5         int countBefore = getRegistry().getBeanDefinitionCount();
 6         // #3.建立XmlReaderContext對象[主要爲了關聯命名空間處理器],並註冊BeanDefinition
 7         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
 8         // 返回新註冊的BeanDefinition對象個數
 9         return getRegistry().getBeanDefinitionCount() - countBefore;
10     }

 分析:node

  • 首先建立BeanDefinitionDocumentReader對象。
  • 獲取已註冊過的BeanDefinition個數。
  • 而後進入核心處理流程,註冊BeanDefinition。
  • 最後返回新註冊的BeanDefinition個數。

XmlBeanDefinitionReader#createBeanDefinitionDocumentReaderspring

1 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
2         return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
3     }

分析:經過反射獲得BeanDefinitionDocumentReader對象。緩存

DefaultListableBeanFactory#getBeanDefinitionCountapp

1     /**
2      * 存儲beanName->BeanDefinition的集合map<br/>
3      * Map of bean definition objects, keyed by bean name.
4      */
5     private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
6 
7     public int getBeanDefinitionCount() {
8         return this.beanDefinitionMap.size();
9     }

分析:邏輯簡單,就是從beanDefinitionMap中獲取當前的size,注意beanDefinitionMap存儲的就是註冊的BeanDefinition集合。ide

DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)函數

1     public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
2         this.readerContext = readerContext;
3         logger.debug("Loading bean definitions");
4         // 獲取XML Document對象的root元素
5         Element root = doc.getDocumentElement();
6         // 執行註冊
7         doRegisterBeanDefinitions(root);
8     }

分析:源碼分析

  • 首先獲取XML Document對象的root元素。
  • 執行註冊。

這裏須要注意一點:registerBeanDefinitions的第二個入參,調用入口以下:post

注意這裏調用了XmlBeanDefinitionReader#createReaderContext:測試

1     /**
2      * 建立一個文檔資源讀取器<br/>
3      * Create the {@link XmlReaderContext} to pass over to the document reader.
4      */
5     public XmlReaderContext createReaderContext(Resource resource) {
6         return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
7                 this.sourceExtractor, this, getNamespaceHandlerResolver());
8     }

分析:

這裏主要關注XmlBeanDefinitionReader#getNamespaceHandlerResolver()函數:

 1 /**
 2      * 主要就是得到默認空間處理器,爲後續解析標籤作準備<br/>
 3      * Lazily create a default NamespaceHandlerResolver, if not set before.
 4      *
 5      * @see #createDefaultNamespaceHandlerResolver()
 6      */
 7     public NamespaceHandlerResolver getNamespaceHandlerResolver() {
 8         if (this.namespaceHandlerResolver == null) {
 9             this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
10         }
11         return this.namespaceHandlerResolver;
12     }
13 
14     /**
15      * Create the default implementation of {@link NamespaceHandlerResolver} used if none is specified.
16      * Default implementation returns an instance of {@link DefaultNamespaceHandlerResolver}.
17      */
18     protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
19         ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());
20         return new DefaultNamespaceHandlerResolver(cl);
21     }

分析:

該函數主要是得到默認空間處理器,爲後續解析標籤作準備。最終切入DefaultNamespaceHandlerResolver中。DefaultNamespaceHandlerResolver中有兩個函數值得咱們關注:

 1 public NamespaceHandler resolve(String namespaceUri) {
 2         // 獲取全部已經配置的Handler映射
 3         Map<String, Object> handlerMappings = getHandlerMappings();
 4         // 根據namespaceUri獲取handler信息:這裏通常都是類路徑
 5         Object handlerOrClassName = handlerMappings.get(namespaceUri);
 6         // 不存在
 7         if (handlerOrClassName == null) {
 8             return null;
 9         // 已經初始化
10         } else if (handlerOrClassName instanceof NamespaceHandler) {
11             return (NamespaceHandler) handlerOrClassName;
12         // 須要進行初始化
13         } else {
14             String className = (String) handlerOrClassName;
15             try {
16                 // 經過反射得到類,並建立NamespaceHandler對象
17                 Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
18                 if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
19                     throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
20                             "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
21                 }
22                 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
23                 // 初始化NameSpaceHandler
24                 namespaceHandler.init();
25                 // 添加到緩存
26                 handlerMappings.put(namespaceUri, namespaceHandler);
27                 return namespaceHandler;
28             } catch (ClassNotFoundException ex) {
29                 throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
30                         "] for namespace [" + namespaceUri + "]", ex);
31             } catch (LinkageError err) {
32                 throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
33                         className + "] for namespace [" + namespaceUri + "]", err);
34             }
35         }
36     }
37 
38 private Map<String, Object> getHandlerMappings() {
39         Map<String, Object> handlerMappings = this.handlerMappings;
40         // 這裏使用了double-check的方式,進行延遲加載
41         if (handlerMappings == null) {
42             synchronized (this) {
43                 handlerMappings = this.handlerMappings;
44                 if (handlerMappings == null) {
45                     if (logger.isTraceEnabled()) {
46                         logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
47                     }
48                     try {
49                         // 讀取handlerMappingsLocation
50                         Properties mappings =
51                                 PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
52                         if (logger.isTraceEnabled()) {
53                             logger.trace("Loaded NamespaceHandler mappings: " + mappings);
54                         }
55                         // 初始化到handlerMappings中
56                         handlerMappings = new ConcurrentHashMap<>(mappings.size());
57                         CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
58                         this.handlerMappings = handlerMappings;
59                     } catch (IOException ex) {
60                         throw new IllegalStateException(
61                                 "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
62                     }
63                 }
64             }
65         }
66         return handlerMappings;
67     }

分析:

  • resolve主要是經過命名空間uri獲得命名空間處理器,若是沒有初始化,則會進行初始化,並緩存。
  • getHandlerMappings函數使用了Double-Check進行延遲加載,獲取全部命名空間處理器。

DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions

 1 protected void doRegisterBeanDefinitions(Element root) {
 2         // Any nested <beans> elements will cause recursion in this method. In
 3         // order to propagate and preserve <beans> default-* attributes correctly,
 4         // keep track of the current (parent) delegate, which may be null. Create
 5         // the new (child) delegate with a reference to the parent for fallback purposes,
 6         // then ultimately reset this.delegate back to its original (parent) reference.
 7         // this behavior emulates a stack of delegates without actually necessitating one.
 8 
 9         // 記錄老的BeanDefinitionParserDelegate對象
10         BeanDefinitionParserDelegate parent = this.delegate;
11 
12         // 建立BeanDefinitionParserDelegate對象,並對delegate進行默認設置
13         this.delegate = createDelegate(getReaderContext(), root, parent);
14 
15         // 檢測<beans/>標籤的命名空間是否爲空,或者是否爲"http://www.springframework.org/schema/beans"
16         if (this.delegate.isDefaultNamespace(root)) {
17             // 處理profile屬性
18             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
19             if (StringUtils.hasText(profileSpec)) {
20                 // 若是profile屬性有值,則使用分隔符進行切分,由於可能有多個profile
21                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
22                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
23                 // 檢測profile是否有效,若是無效,則不進行註冊
24                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
25                     if (logger.isInfoEnabled()) {
26                         logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
27                                 "] not matching: " + getReaderContext().getResource());
28                     }
29                     return;
30                 }
31             }
32         }
33         // 解析xml前置處理,該方法爲空,主要留給用戶自定義處理,加強擴展性
34         preProcessXml(root);
35         // 核心函數,進行xml解析
36         parseBeanDefinitions(root, this.delegate);
37         // 解析xml後置處理,該方法也爲空,主要留給用戶自定義處理,加強擴展性
38         postProcessXml(root);
39         // 將delegate回到老的BeanDefinitionParserDelegate對象
40         this.delegate = parent;
41     }

分析:

  • 首先記錄舊的BeanDefinitionParserDelegate,而後建立一個新的BeanDefinitionParserDelegate對象,由於對BeanDefinition的解析會進行委託。
  • 檢測<beans/>標籤的正確性,處理profile屬性。
  • preProcessXml:解析xml的前置處理,默認爲空,主要留給用戶自定義實現,加強擴展性;postProcessXml:解析xml的後置處理,默認也爲空,一樣留給用戶自定義實現。
  • parseBeanDefinitions:解析xml的核心函數,將在下面進行詳細分析。

DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

 1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
 2         // 若是根節點使用默認命名空間,則執行默認解析
 3         if (delegate.isDefaultNamespace(root)) {
 4             NodeList nl = root.getChildNodes();
 5             // 遍歷子節點
 6             for (int i = 0; i < nl.getLength(); i++) {
 7                 Node node = nl.item(i);
 8                 if (node instanceof Element) {
 9                     Element ele = (Element) node;
10                     // 若是該節點使用默認命名空間,則執行默認解析
11                     if (delegate.isDefaultNamespace(ele)) {
12                         parseDefaultElement(ele, delegate);
13                         // 若是該節點使用非默認命名空間,則執行自定義解析
14                     } else {
15                         delegate.parseCustomElement(ele);
16                     }
17                 }
18             }
19             // 不然使用自定義解析根節點
20         } else {
21             delegate.parseCustomElement(root);
22         }
23     }

分析:

首先判斷根節點是否使用默認命名空間:

  • 若是是默認命名空間,則遍歷其子節點進行解析。
  • 若是不是默認命名空間,則直接使用parseCustomElement進行解析。

DefaultBeanDefinitionDocumentReader#parseDefaultElement

 1 /**
 2      * 解析默認標籤
 3      *
 4      * @param ele      當前元素節點
 5      * @param delegate BeanDefinition解析委託
 6      */
 7     private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
 8         // import標籤
 9         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
10             // 主要流程獲取import標籤的source屬性,而後經過loadBeanDefinitions加載BeanDefinition
11             importBeanDefinitionResource(ele);
12         } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // alias標籤
13             processAliasRegistration(ele);
14         } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // bean標籤,主要解析標籤
15             processBeanDefinition(ele, delegate);
16         } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // beans標籤
17             // recurse
18             doRegisterBeanDefinitions(ele);
19         }
20     }

分析:

默認標籤的解析分爲4個分支:①import;②alias;③bean;④beans標籤(進行遞歸,再進行解析)。這裏咱們主要分析平常中最經常使用的bean標籤,其餘標籤解析的大體流程差很少,後面進行補充。

DefaultBeanDefinitionDocumentReader#processBeanDefinition

 1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
 2         // 進行bean標籤解析
 3         // 若是解析成功,則返回BeanDefinitionHolder,BeanDefinitionHolder爲name和alias的BeanDefinition對象
 4         // 若是解析失敗,則返回null
 5         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
 6         if (bdHolder != null) {
 7             // 進行標籤處理,主要對bean標籤的相關屬性進行處理 如: p:name="測試用例"
 8             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
 9             try {
10                 // 註冊BeanDefinition
11                 // Register the final decorated instance.
12                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
13             } catch (BeanDefinitionStoreException ex) {
14                 getReaderContext().error("Failed to register bean definition with name '" +
15                         bdHolder.getBeanName() + "'", ele, ex);
16             }
17             // 發出響應時間,通知監聽器,已完成該bean標籤的解析
18             // Send registration event.
19             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
20         }
21     }

分析:

  • 首先使用委託對bean標籤進行基礎解析(核心處理流程)。
  • 解析成功後,再處理bean標籤的一些其餘屬性。
  • 最後註冊BeanDefintion。

BeanDefinitionParserDelegate#parseBeanDefinitionElement

 1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
 2         return parseBeanDefinitionElement(ele, null);
 3     }
 4 
 5 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
 6         // 解析id和name屬性
 7         String id = ele.getAttribute(ID_ATTRIBUTE);
 8         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
 9 
10         // 計算別名集合
11         List<String> aliases = new ArrayList<>();
12         if (StringUtils.hasLength(nameAttr)) {
13             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
14             aliases.addAll(Arrays.asList(nameArr));
15         }
16 
17         // beanName,優先使用id
18         String beanName = id;
19         // 若beanName爲空,則使用alias的第一個
20         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
21             // 將alias第一個元素移除別名集合
22             beanName = aliases.remove(0);
23             if (logger.isTraceEnabled()) {
24                 logger.trace("No XML 'id' specified - using '" + beanName +
25                         "' as bean name and " + aliases + " as aliases");
26             }
27         }
28 
29         // 檢查beanName的惟一性
30         if (containingBean == null) {
31             checkNameUniqueness(beanName, aliases, ele);
32         }
33 
34         // 解析bean標籤的屬性,構造AbstractBeanDefinition
35         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
36         if (beanDefinition != null) {
37             // 若是beanName爲空
38             if (!StringUtils.hasText(beanName)) {
39                 try {
40                     // 若是containingBean不爲null
41                     if (containingBean != null) {
42                         // 生成惟一的beanName
43                         beanName = BeanDefinitionReaderUtils.generateBeanName(
44                                 beanDefinition, this.readerContext.getRegistry(), true);
45                     } else {
46                         // 生成惟一的beanName
47                         beanName = this.readerContext.generateBeanName(beanDefinition);
48                         // Register an alias for the plain bean class name, if still possible,
49                         // if the generator returned the class name plus a suffix.
50                         // This is expected for Spring 1.2/2.0 backwards compatibility.
51                         // 判斷beanName是否被使用
52                         String beanClassName = beanDefinition.getBeanClassName();
53                         if (beanClassName != null &&
54                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
55                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
56                             aliases.add(beanClassName);
57                         }
58                     }
59                     if (logger.isTraceEnabled()) {
60                         logger.trace("Neither XML 'id' nor 'name' specified - " +
61                                 "using generated bean name [" + beanName + "]");
62                     }
63                 } catch (Exception ex) {
64                     error(ex.getMessage(), ele);
65                     return null;
66                 }
67             }
68             // 建立BeanDefinitionHolder對象
69             String[] aliasesArray = StringUtils.toStringArray(aliases);
70             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
71         }
72 
73         return null;
74     }

分析: 

  • 獲取bean標籤的id與name屬性,spring在解析bean的時候,優先使用的id值。
  • 檢查beanName的惟一性,若是不惟一,則會報錯。
  • (核心)解析bean的屬性,構造AbstractBeanDefinition對象。
  • 若是beanDefiniton對象的beanName爲空,還要爲其生成一個beanName,爲註冊BeanDefinition作準備。
  • 最後返回BeanDefinitionHolder對象。

BeanDefinitionParserDelegate#parseBeanDefinitionElement

 1 public AbstractBeanDefinition parseBeanDefinitionElement(
 2             Element ele, String beanName, @Nullable BeanDefinition containingBean) {
 3 
 4         // 爲解析bean元素加一個狀態
 5         this.parseState.push(new BeanEntry(beanName));
 6 
 7         // 解析class屬性
 8         String className = null;
 9         if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
10             className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
11         }
12         // 解析parent屬性
13         String parent = null;
14         if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
15             parent = ele.getAttribute(PARENT_ATTRIBUTE);
16         }
17 
18         try {
19             // 建立承載屬性的AbstractBeanDefinition對象
20             AbstractBeanDefinition bd = createBeanDefinition(className, parent);
21             // 解析bean的各類默認屬性
22             parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
23             // 提取description
24             bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
25 
26             // 這裏會解析bean標籤內部的不少子元素,放入bd中
27 
28             // #1.解析元數據 <meta/>
29             parseMetaElements(ele, bd);
30             // #2.解析lookup-method屬性 <lookup-method/>
31             // lookup-method:獲取器注入,把一個方法聲明爲返回某種類型的bean,但方法的實際返回的bean是在配置文件裏配置的
32             parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
33 
34             // #3.解析replace-method屬性 <replace-method/>
35             // replace-method:可在運行時調用新的方法替換現有的方法,還能動態的更新原有方法的邏輯
36             parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
37 
38             // #4.解析構造函數參數 <constructor-arg/>
39             parseConstructorArgElements(ele, bd);
40             // #5.解析property子元素 <property/>
41             parsePropertyElements(ele, bd);
42             // #6.解析qualifier子元素 <qualifier/>
43             parseQualifierElements(ele, bd);
44 
45             // 設置resource
46             bd.setResource(this.readerContext.getResource());
47             bd.setSource(extractSource(ele));
48 
49             return bd;
50         } catch (ClassNotFoundException ex) {
51             error("Bean class [" + className + "] not found", ele, ex);
52         } catch (NoClassDefFoundError err) {
53             error("Class that bean class [" + className + "] depends on not found", ele, err);
54         } catch (Throwable ex) {
55             error("Unexpected failure during bean definition parsing", ele, ex);
56         } finally {
57             this.parseState.pop();
58         }
59 
60         return null;
61     }

分析:

  • 首先獲取bean標籤的class和parent屬性,用於建立承載屬性的AbstractBeanDefinition對象[由這兩個屬性就能夠建立AbstractBeanDefinition對象了]。
  • 接下來就是對bean標籤進行各類解析,並將解析的數據賦值到AbstractBeanDefinition中。

BeanDefinitionParserDelegate#createBeanDefinition

 1 protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
 2             throws ClassNotFoundException {
 3 
 4         return BeanDefinitionReaderUtils.createBeanDefinition(
 5                 parentName, className, this.readerContext.getBeanClassLoader());
 6     }
 7 
 8 
 9 //BeanDefinitionReaderUtils#creatBeanDefinition
10 
11 public static AbstractBeanDefinition createBeanDefinition(
12             @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
13 
14         // 建立GenericBeanDefinition對象
15         GenericBeanDefinition bd = new GenericBeanDefinition();
16         // 設置parentName
17         bd.setParentName(parentName);
18         // 在className不爲空的狀況下,進行相關屬性的設置
19         if (className != null) {
20             // 若是classLoader不爲空,這裏就會直接經過反射加載類 ?爲了提高速度
21             if (classLoader != null) {
22                 bd.setBeanClass(ClassUtils.forName(className, classLoader));
23             }
24             // 設置beanClassName的名字
25             else {
26                 bd.setBeanClassName(className);
27             }
28         }
29         return bd;
30     }

分析:

BeanDefinition的建立是經過BeanDefinitionReaderUtils#createBeanDefinition方法實現的,代碼邏輯簡單,主要注意生成的BeanDefinition對象是GenericBeanDefinition

BeanDefinitionParserDelegate#parseBeanDefinitionAttributes

 1 public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
 2                                                                 @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
 3         // 若是有singleton屬性則拋出異常,由於singleton屬性已進行升級
 4         if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
 5             error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
 6             // 解析scope屬性
 7         } else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
 8             bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
 9             // 若是BeanDefinition不爲空,則使用當前BeanDefinition的scope
10         } else if (containingBean != null) {
11             // Take default from containing bean in case of an inner bean definition.
12             bd.setScope(containingBean.getScope());
13         }
14         // 解析abstract屬性
15         if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
16             bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
17         }
18 
19         // 解析lazy-init屬性 lazy-init屬性默認爲false
20         String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
21         if (isDefaultValue(lazyInit)) {
22             lazyInit = this.defaults.getLazyInit();
23         }
24         bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
25 
26         // 解析autowire屬性
27         String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
28         bd.setAutowireMode(getAutowireMode(autowire));
29 
30         // 解析depends-on屬性
31         if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
32             String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
33             bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
34         }
35 
36         // 解析autowire-candidate屬性
37         String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
38         if (isDefaultValue(autowireCandidate)) {
39             String candidatePattern = this.defaults.getAutowireCandidates();
40             if (candidatePattern != null) {
41                 String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
42                 bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
43             }
44         } else {
45             bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
46         }
47 
48         // 解析primary屬性
49         if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
50             bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
51         }
52 
53         // 解析init-method屬性 設置bean的初始值方法
54         if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
55             String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
56             bd.setInitMethodName(initMethodName);
57         } else if (this.defaults.getInitMethod() != null) {
58             bd.setInitMethodName(this.defaults.getInitMethod());
59             bd.setEnforceInitMethod(false);
60         }
61 
62         // 解析destroy-method屬性
63         if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
64             String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
65             bd.setDestroyMethodName(destroyMethodName);
66         } else if (this.defaults.getDestroyMethod() != null) {
67             bd.setDestroyMethodName(this.defaults.getDestroyMethod());
68             bd.setEnforceDestroyMethod(false);
69         }
70 
71         // 解析factory-method屬性
72         if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
73             bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
74         }
75         // 解析factory-bean屬性
76         if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
77             bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
78         }
79 
80         return bd;
81     }

分析:

該函數是對bean標籤的默認屬性作解析,最終解析後的值封裝在BeanDefinition中,代碼邏輯簡單,函數中已給出相應註釋。這裏要注意一點lazy-init屬性的默認值爲false。

介於篇幅緣由,這裏不在分析bean標籤默認屬性的解析過程,後續會對一些重要的方法進行補充,下面將分析BeanDefinition的註冊過程。

總結

本文主要分析了BeanDefinition註冊以前的一些準備工做,還未進入核心流程,後面將進入BeanDefinition註冊的核心流程。

ps:筆者但願每篇文章不要寫太長,儘可能作到短小精悍。


by Shawn Chen,2018.12.8日,下午。

相關文章
相關標籤/搜索