前言:在【spring源碼分析】IOC容器初始化(二)中已經得到了XML配置檔案的Document執行個體,下面分析bean的注冊過程。
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 }
分析:
- 首先建立BeanDefinitionDocumentReader對象。
- 擷取已注冊過的BeanDefinition個數。
- 然後進入核心處理流程,注冊BeanDefinition。
- 最後傳回新注冊的BeanDefinition個數。
XmlBeanDefinitionReader#createBeanDefinitionDocumentReader
1 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
2 return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
3 }
分析:通過反射得到BeanDefinitionDocumentReader對象。
DefaultListableBeanFactory#getBeanDefinitionCount
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集合。
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的第二個入參,調用入口如下:

注意這裡調用了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對象。
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日,下午。