前言
此源碼其實是在4月中旬就看了,而且當初也寫了一份word文檔,但不打算直接把word發上來。還是跟着以前的筆記、跟蹤代碼邊看邊寫吧。
其實當初看源碼的理由很簡單,1、才進新公司,比較有空閑。2、面試老是問spring的問題,我理論又不好,所以想看下。
但現在,我重新看的目的其實不在於其實現原理,而是想學習和寫出好的編碼風格。(當初大概花了1周看,記得那時把看到的都理解深刻了,但現在基本不記得什么了。畢竟開發用不到)
一、如何開始閱讀源碼?
最初我也一頭霧水,不知道從哪開始看、怎么看、看源碼的目的是什么等等。
1、從哪開始看?
針對本文的話,還是可以知道入口是哪的(后面給出demo),所以我還知道從哪開始開起。
2、怎么看?
我都是跟蹤代碼,一步一步的看的。(其效率很慢,但暫時也只會這么看)
3、目的?
當初我只關注spring是怎么讀取xml配置、怎么如入bean。但發現,即使我當初看的時候理解在深刻,一個月不回想,再過不多久就不知道都是些什么了。
而且,現在我更想學習的是好的編碼風格,如何才能寫出好看、好理解、易擴展的代碼(即遵循SOLID原則)
(開發設計原則 此文章是我較早學習整理的,其正文就是我看到較好的一篇blog內容。)
二、入口代碼demo spring版本3.2.16.RELEASE
public class Demo0102Run { // static String path = new Demo0102Run().getClass().getClassLoader().getResource("").getPath(); public static void main(String[] args) { // System.out.println(System.getProperty("user.dir")); //step1: 讀取spring的xml (spring核心的是BeanFactory) /* 把資源文件封裝為Spring的Resource * spring把資源文件封裝成統一的Resource進行管理,和提供一些基本的方法。 */ Resource resource = new ClassPathResource("spring-demo0102.xml",Demo0102Run.class); // System.out.println(resource.isOpen()); /* 加載資源文件,把xml中的bean definition注冊到:1.把Resource再次封裝為EncodedResource * */ XmlBeanFactory factory = new XmlBeanFactory(resource); // BeanFactory factory = new XmlBeanFactory(resource); //step2:根據讀取的xml配置,注入對應的bean /* * 需要了解 BeanFactory和FactoryBean的區別:http://chenzehe.iteye.com/blog/1481476 * 備注01: 如果是beanName的命名是"&"開頭,ex:"&demo0102Bean" spring會有別的處理。 * a. 對於beanInstance是FactoryBean的,會返回FactoryBean的的實例。並不是返回通過FactoryBean創建的bean實例 */ Demo0102Bean bean = (Demo0102Bean) factory.getBean("demo0102Bean"); System.out.println(bean.getResult()); } }
public class Demo0102Bean { private String result = "Demo0102Bean result String!"; public String getResult() { return result; } public void setResult(String result) { this.result = result; } }
通過demo,可以很好的跟蹤進代碼,然后一步一步分析。(我是這樣看的,不一定可取)
三、spring讀取xml (為了好看,源碼中部分注釋被刪除、部分代碼被簡寫)
Resource resource = new ClassPathResource("spring-demo0102.xml",Demo0102Run.class);
3.1 new ClassPathResource("spring-demo0102.xml",Demo0102Run.class);
構造一個ClassPathResource(),根據ClassPathResource的類結構可知:實際是構造了Resource資源文件的實例對象。
在后續的資源處理就可以利用Resource提供各種的服務來操作。
在demo中,有了ClassPathResource(即Resource)就可以對XmlBeanFactory進行初始化new XmlBeanFactory(...)。
/** Resource.class的實現類,使用給定的ClassLoader或Class去加載資源文件。 * 順序是Class、ClassLoader、null, * 詳見ClassPathResource.getInputStream() */ public class ClassPathResource extends AbstractFileResolvingResource { private final String path; private ClassLoader classLoader; private Class<?> clazz; /** 創建一個 new ClassPathResource(); Create a new {@code ClassPathResource} for {@code Class} usage.The path can be relative to the given class,
or absolute within the classpath via a leading slash. @param path relative or absolute path within the class path @param clazz the class to load resources with @see java.lang.Class#getResourceAsStream */ public ClassPathResource(String path, Class<?> clazz) {// 還有別的構造函數,詳見源碼; 區別是,是否設置了class、classLoader Assert.notNull(path, "Path must not be null"); this.path = StringUtils.cleanPath(path); this.clazz = clazz; }
public InputStream getInputStream() throws IOException { InputStream is; //if else判斷根據用Class\ClassLoader去讀取資源文件.構造函數中設置 if (this.clazz != null) is = this.clazz.getResourceAsStream(this.path); else if (this.classLoader != null) is = this.classLoader.getResourceAsStream(this.path); else is = ClassLoader.getSystemResourceAsStream(this.path); if (is == null) throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist"); return is; } }
通過ClassPathResource的UML可知道其繼承關系(本來顯示全名的,但不知道怎么弄)。
根據此關系及ClassPathResource實際源碼,可以發現ClassPathResource實現了Resource中部分抽象方法。
(在ClassPathResource源碼,並未實現全部的Resource。一部分是AbstractResource中實現的,但AbstractResource部份不是真實的實現。e.g.: isOpen();AbstractResource總是返回false。 )
3.1.1 Resource資源是如何被封裝的?
在demo中是通過new ClassPathResource(...); 通過Resource的關系圖,也可以用別的來封裝。
3.1.2 Spring為什么需要封裝Resource?
Spring用Resource接口對其內部要用到的資源進行統一的處理。及定義一些基本方法。
3.1.3 Spring中的Resource及 InputStreamSource
通過圖Resource類的UML可以看出,對於不同來源的資源文件都有相應的Resource實現:
- 文件 :FileSystemResource.class
- Classpath資源 :ClassPathResource.class
- URL資源 :UrlResource.class
- InputStream資源 :InputStreamResource.class
- Byte數組 :ByteArrayResource.class
- 等等

/** * Interface for a resource descriptor that abstracts from the actual * type of underlying resource, such as a file or class path resource. * * <p>An InputStream can be opened for every resource if it exists in * physical form, but a URL or File handle can just be returned for * certain resources. The actual behavior is implementation-specific. */ public interface Resource extends InputStreamSource { /** 返回資源是否存在 */ boolean exists(); /** 返回資源內容是否可讀 */ boolean isReadable(); /** 返回這個資源是否有已打開流的處理。 * 如果為true,則此InputStream就不能被多次讀取, *而且只能被讀取和關閉以避免資源泄漏 */ boolean isOpen(); /** 轉換Resource到URL * Return a URL handle for this resource. * @throws IOException if the resource cannot be resolved as URL, * i.e. if the resource is not available as descriptor */ URL getURL() throws IOException; /** 轉換Resource到URI * Return a URI handle for this resource. * @throws IOException if the resource cannot be resolved as URI, * i.e. if the resource is not available as descriptor */ URI getURI() throws IOException; /** 轉換Resource到File * Return a File handle for this resource. * @throws IOException if the resource cannot be resolved as absolute file path, i.e. if the resource is not available in a file system */ File getFile() throws IOException; /** 返回該資源的內容長度 * Determine the content length for this resource. * @throws IOException if the resource cannot be resolved * (in the file system or as some other known physical resource type) */ long contentLength() throws IOException; /** * Determine the last-modified timestamp for this resource. * @throws IOException if the resource cannot be resolved * (in the file system or as some other known physical resource type) */ long lastModified() throws IOException; /** 創建資源相對於這個資源 * Create a resource relative to this resource. * @param relativePath the relative path (relative to this resource) * @return the resource handle for the relative resource * @throws IOException if the relative resource cannot be determined */ Resource createRelative(String relativePath) throws IOException; /** * Determine a filename for this resource, i.e. typically the last * part of the path: for example, "myfile.txt". * <p>Returns {@code null} if this type of resource does not * have a filename. */ String getFilename(); /** 返回該資源的描述,用於錯誤處理中打印信息。 * Return a description for this resource, * to be used for error output when working with the resource. * <p>Implementations are also encouraged to return this value * from their {@code toString} method. * @see Object#toString() */ String getDescription(); } Resource類源碼

public interface InputStreamSource { /** * @return the input stream for the underlying resource (must not be null) */ InputStream getInputStream() throws IOException; }
3.1.4 Resource讀取資源的具體實現
以getInputStream()為例,在ClassPathResource中的實現方式是通過class或者classLoader提供的底層方法調用的,返回InputStream。
當通過Resource完成了對配置文件進行封裝后,配置文件的讀取工作就完全交給了XmlBeanDefinitionReader來處理。
/** * This implementation opens an InputStream for the given class path resource. * @see java.lang.ClassLoader#getResourceAsStream(String) * @see java.lang.Class#getResourceAsStream(String) */ public InputStream getInputStream() throws IOException { InputStream is; // if else 判斷根據用Class 、 ClassLoader去讀取資源文件;在構造函數中設置 if (this.clazz != null) { is = this.clazz.getResourceAsStream(this.path); } else if (this.classLoader != null) { is = this.classLoader.getResourceAsStream(this.path); } else { is = ClassLoader.getSystemResourceAsStream(this.path); } if (is == null) { throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist"); } return is; }
3.2 new XmlBeanFactory(resource)

public class XmlBeanFactory extends DefaultListableBeanFactory { private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); /** * Create a new XmlBeanFactory with the given resource, * which must be parsable using DOM. * @param resource XML resource to load bean definitions from * @throws BeansException in case of loading or parsing errors */ public XmlBeanFactory(Resource resource) throws BeansException { this(resource, null); } /** * Create a new XmlBeanFactory with the given input stream, * which must be parsable using DOM. * @param resource XML resource to load bean definitions from * @param parentBeanFactory parent bean factory * @throws BeansException in case of loading or parsing errors */ public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { /* 調用父類的構造函數,進行了一個中要處理。 * 在 AbstractAutowireCapableBeanFactory.class構造函數中有如下設置: * ignoreDependencyInterface(BeanNameAware.class); * ignoreDependencyInterface(BeanFactoryAware.class); * ignoreDependencyInterface(BeanClassLoaderAware.class); * * ignoreDependencyInterface(...)方法描述: 忽略給定依賴接口的自動裝配功能 * 具體看方法。 */ super(parentBeanFactory);//此處調用的是:AbstractAutowireCapableBeanFactory.class /* * XmlBeanFactory方式整個資源加載的核心 */ this.reader.loadBeanDefinitions(resource); } }

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { public DefaultListableBeanFactory(BeanFactory parentBeanFactory) { super(parentBeanFactory); } }

3.2.1 為什么要ignoreDependencyInterface(...)?
當A中有屬性B時,在spring獲取A的Bean的時候,如果屬性B還沒有初始化,則spring會自動初始化B(這是spring的一個重要特性);
但是,某些情況下B不會被初始化,其中一種情況就是B實現了BeanNameAware接口。
ignoreDependencyInterface中注釋表明了,忽略給定依賴接口的自動裝配功能。典型的是通過其他方式解析ApplicationContext。
比如:BeanFactory通過BeanFactoryAware進行注入,或者ApplicationContext通過ApplicationContextAware進行注入。
(這是當初記下的,現在回頭看。完全不知道說的什么…>.<!)
3.2.2 (核心)new XmlBeanDefinitionReader(this).loadBeanDefinitions(resource); XmlBeanDefinitionReader方式整個資源加載的核心。
// 整個xml加載的核心代碼 public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { /** * Load bean definitions from the specified XML file. * @param resource the resource descriptor for the XML file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { /* * 1:把Resource進一步封裝為EncodedResource; * 原因:考慮到Resource可能對編碼有要,所以EncodedResource可以指定encoding編碼、charset字符集。 * EncodedResource中的重要方法是getReader(),返回InputStreamReader.class(java.io.Reader的子類) * 2:再調用加載資源文件的方法。 */ return loadBeanDefinitions(new EncodedResource(resource)); } //記錄已經加載過的資源。注意:用了ThreadLocal private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded"); /** * Load bean definitions from the specified XML file. * @param encodedResource the resource descriptor for the XML file, * allowing to specify an encoding to use for parsing the file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from "+ encodedResource.getResource()); } // 通過類屬性resourcesCurrentlyBeingLoaded 記錄已加載的資源。 Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } //添加新資源到類屬性;最后finally中有remove() 處理循環加載exception if (!currentResources.add(encodedResource)) { //循環加載exception throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { // 封裝的EncodeResource先獲取Resource,在通過Resource獲取InputStream InputStream inputStream = encodedResource.getResource().getInputStream(); try { // 把InputStream封裝為InputSource;org.xml.sax.InputSource不屬於Spring InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } // doLoadBeanDefinitions才是核心加載資源文件 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } }catch (IOException ex) { throw new BeanDefinitionStoreException("IOException parsing XML document from "+ encodedResource.getResource(), ex); } // 問題01:finally的作用是什么? 原以為resourcesCurrentlyBeingLoaded類似緩存的作用,但在finally看來應該不是,那resourcesCurrentlyBeingLoaded實際作用是什么? finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } private DocumentLoader documentLoader = new DefaultDocumentLoader(); private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger); /** 實際上真正的去加載bean的定義,從指定的xml文件中 * Actually load bean definitions from the specified XML file. * @param inputSource the SAX InputSource to read from * @param resource the resource descriptor for the XML file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { // 注冊核心01: 獲取對xml文件的驗證模式 int validationMode = getValidationModeForResource(resource); /* 注冊核心02:利用spring核心的DocumentLoader加載xml,得到對應的org.w3c.dom.Document * inputSource:就是通過Resource.getInputStream(),在用InputStream構造InputSource * getEntityResolver():得到一個實體解析器(org.xml.sax.EntityResolver),可以通過AbstractBeanDefinitionReader.setResourceLoader()設置。 * this.errorHandler:xml錯誤處理。(org.xml.sax.ErrorHandler,不屬於spring) * validationMode:xml驗證模式 * isNamespaceAware():Return whether or not the XML parser should be XML namespace aware. */ Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); /* * 注冊核心03:根據返回的Document注冊bean的信息。(重點,解析配置文件,然后注冊bean信息) * (理解注冊、注入,lyn個人理解: * 注冊:好比創建了一個登陸帳號,保存到了數據庫 * 注入:根據輸入的登陸信息,去數據庫找,找到就返回(把bean實例化) * ) */ return registerBeanDefinitions(doc, resource); } catch (*Exception ex) { throw new *Exception(...); } } /** 獲取指定的Resource的驗證模式,如果沒有配置明確的驗證模式,則使用自動檢測 * Gets the validation mode for the specified {@link Resource}. If no explicit validation mode has been configured then the validation mode is * {@link #detectValidationMode detected}. * * <p>Override this method if you would like full control over the validation mode, even when something other than {@link #VALIDATION_AUTO} was set. */ protected int getValidationModeForResource(Resource resource) { int validationModeToUse = getValidationMode(); // 如果手動指定了驗證模式,則使用指定的 //(可在XmlBeanDefinitionReader.setValidationMode()方法設置) if (validationModeToUse != VALIDATION_AUTO) { return validationModeToUse; } // 如果未指定,則使用自動檢測 int detectedMode = detectValidationMode(resource); if (detectedMode != VALIDATION_AUTO) { return detectedMode; } // Hmm, we didn't get a clear indication... Let's assume XSD, // since apparently no DTD declaration has been found up until // detection stopped (before finding the document's root tag). return VALIDATION_XSD; } private boolean namespaceAware = false; // 默認false /** * Return whether or not the XML parser should be XML namespace aware. */ public boolean isNamespaceAware() { return this.namespaceAware; } /** 返回EntityResolver的使用,構建一個默認的EntityResolver(實體解析器) * Return the EntityResolver to use, building a default resolver * if none specified. 如果未指定 * getResourceLoader()、getBeanClassLoader()都是AbstractBeanDefinitionReader.class中的方法。 */ protected EntityResolver getEntityResolver() { if (this.entityResolver == null) { // 確定默認使用的EntityResolver(實體解析器) // Determine default EntityResolver to use. ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader != null) this.entityResolver = new ResourceEntityResolver(resourceLoader); else this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader()); } return this.entityResolver; } }

/** 對Resource進行封裝,考慮到Resource可能對編碼有要,所以EncodedResource可以指定encoding編碼、charset字符集。 * 當指定后,獲取Reader會根據charset、encoding、default的順序去獲取InputStreamReader,看具體代碼getReader(); * Holder that combines a Resource descriptor with a specific encoding * or Charset to be used for reading from the resource. * * <p>Used as an argument for operations that support reading content with a specific encoding, typically via a java.io.Reader. */ public class EncodedResource { private final Resource resource; private final String encoding; private final Charset charset; /** * Create a new EncodedResource for the given Resource, * not specifying an explicit encoding or Charset. * @param resource the Resource to hold; never null */ public EncodedResource(Resource resource) { this(resource, null, null); } /** * Create a new EncodedResource for the given Resource, * using the specified encoding. * @param resource the Resource to hold; never null * @param encoding the encoding to use for reading from the resource */ public EncodedResource(Resource resource, String encoding) { this(resource, encoding, null); } /** * Create a new {@code EncodedResource} for the given {@code Resource}, * using the specified {@code Charset}. * @param resource the {@code Resource} to hold; never {@code null} * @param charset the {@code Charset} to use for reading from the resource */ public EncodedResource(Resource resource, Charset charset) { this(resource, null, charset); } private EncodedResource(Resource resource, String encoding, Charset charset) { super(); Assert.notNull(resource, "Resource must not be null"); this.resource = resource; this.encoding = encoding; this.charset = charset; } /** * Return the {@code Resource} held by this {@code EncodedResource}. */ public final Resource getResource() { return this.resource; } /** * Return the encoding to use for reading from the {@linkplain #getResource() resource}, * or {@code null} if none specified. */ public final String getEncoding() { return this.encoding; } /** * Return the {@code Charset} to use for reading from the {@linkplain #getResource() resource}, * or {@code null} if none specified. */ public final Charset getCharset() { return this.charset; } /** * Determine whether a {@link Reader} is required as opposed to an {@link InputStream}, * i.e. whether an {@linkplain #getEncoding() encoding} or a {@link #getCharset() Charset} * has been specified. * @see #getReader() * @see #getInputStream() */ public boolean requiresReader() { return (this.encoding != null || this.charset != null); } /** 當設置了encoding或者charset后,會通過指定的去獲取InputStreamReader * Open a {@code java.io.Reader} for the specified resource, using the specified * {@link #getCharset() Charset} or {@linkplain #getEncoding() encoding} * (if any). * @throws IOException if opening the Reader failed * @see #requiresReader() * @see #getInputStream() */ public Reader getReader() throws IOException { if (this.charset != null) { return new InputStreamReader(this.resource.getInputStream(), this.charset); } else if (this.encoding != null) { return new InputStreamReader(this.resource.getInputStream(), this.encoding); } else { return new InputStreamReader(this.resource.getInputStream()); } } /** * Open a java.io.InputStream for the specified resource, ignoring any specified {@link #getCharset() Charset} or {@linkplain #getEncoding() encoding}. * @throws IOException if opening the InputStream failed * @see #requiresReader() * @see #getReader() */ public InputStream getInputStream() throws IOException { return this.resource.getInputStream(); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof EncodedResource) { EncodedResource that = (EncodedResource) obj; return (this.resource.equals(that.resource) && ObjectUtils.nullSafeEquals(this.charset, that.charset) && ObjectUtils.nullSafeEquals(this.encoding, that.encoding)); } return false; } @Override public int hashCode() { return this.resource.hashCode(); } @Override public String toString() { return this.resource.toString(); } }
3.2.3 注冊核心01: 獲取對xml文件的驗證模式
為了保證xml文件的正確性,一般對xml的驗證模式有2種:
(1) DTD:Document Type Definition ,類型定義
(2) XSD:XML Schemas Definition ,XML結構定義
問題02:DTD和XSD驗證XML文件的區別,待看。
在spring,XmlBeanDefinitionReader中的setValidationMode(int x);可以設置xml的驗證方式。如果未設置,則用自動檢測模式。
protected int XmlBeanDefinitionReader.getValidationModeForResource(Resource resource) 可以獲取xml的驗證方式。
在其內部又把自動檢測detectValidationMode(Resource resource)交給了專門用於處理xml驗證的類XmlValidationModeDetector.class
在XmlValidationModeDetector.class內部,判斷xml驗證模式的標准是:xml中是否包含"DOCTYPE",如果包含則 DTD驗證,否則用XSD;

<!-- 包含"DOCTYPE",用 DTD驗證 --> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <!-- 未包含"DOCTYPE",用 XSD驗證 --> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd" >
public class XmlValidationModeDetector { public int detectValidationMode(InputStream inputStream) throws IOException { // Peek into the file to look for DOCTYPE. 在讀取文件中查找"DOCTYPE" BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); try { boolean isDtdValidated = false; String content; while ((content = reader.readLine()) != null) { content = consumeCommentTokens(content); //讀取的行是null 或者 是注釋 則略過 if (this.inComment || !StringUtils.hasText(content)) { continue; } //如果包含DOCTYPE 則驗證模式是DTD,否則XSD if (hasDoctype(content)) { isDtdValidated = true;break; } //讀取到<開始符號,驗證模式會在開始符號之前(分析xml結構) if (hasOpeningTag(content)) { // End of meaningful data... break; } } return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD); } catch (CharConversionException ex) { // Choked on some character encoding... // Leave the decision up to the caller. return VALIDATION_AUTO; } finally { reader.close(); } } /** * Does the supplied content contain an XML opening tag. If the parse state is currently in an XML comment then this method always returns false. It is expected that all comment tokens will have consumed for the supplied content before passing the remainder to this method. */ private boolean hasOpeningTag(String content) { if (this.inComment) { return false;} int openTagIndex = content.indexOf('<'); // Character.isLetter 確定字符是字母,是字母返回true return (openTagIndex > –1 && (content.length() > openTagIndex + 1)
&& Character.isLetter(content.charAt(openTagIndex + 1)) ); } }
結合上面的2種xml理解 hasOpeningTag(content):
因為都是行讀取reader.readLine();
第一行:<?xml version="1.0" encoding="UTF-8"?>
openTagIndex > -1 ,0 > -1:true
(content.length() > openTagIndex + 1) :true
Character.isLetter(“?”) :?不是字母false
第二行:<beans xmlns="http://www.springframework.org/schema/beans"
openTagIndex > -1 ,0 > -1:true
(content.length() > openTagIndex + 1) :true
Character.isLetter(“b”) :true
此時會結束while循環,執行
return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
3.2.4 最核心加載xml
/* 注冊核心02:利用spring核心的DocumentLoader加載xml,得到對應的org.w3c.dom.Document
* inputSource:就是通過Resource.getInputStream(),在用InputStream構造InputSource
* getEntityResolver():得到一個實體解析器(org.xml.sax.EntityResolver),可以通過AbstractBeanDefinitionReader.setResourceLoader()設置。
* this.errorHandler:xml錯誤處理。(org.xml.sax.ErrorHandler,不屬於spring)
* validationMode:xml驗證模式
* isNamespaceAware():Return whether or not the XML parser should be XML namespace aware.
*/
Document doc = this.documentLoader.loadDocument( inputSource,
getEntityResolver(),
this.errorHandler,
validationMode,
isNamespaceAware());
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { // DocumentLoader是一個接口,spring唯一實現類是DefaultDocumentLoader; private DocumentLoader documentLoader = new DefaultDocumentLoader(); /** 可以自己實現DocumentLoader, 然后通過該方法設置documentLoader * Specify the {@link DocumentLoader} to use. * <p>The default implementation is {@link DefaultDocumentLoader} * which loads {@link Document} instances using JAXP. */ public void setDocumentLoader(DocumentLoader documentLoader) { this.documentLoader = (documentLoader != null ? documentLoader : new DefaultDocumentLoader()); } }
public class DefaultDocumentLoader implements DocumentLoader { /** JAXP attribute used to configure the schema language for validation. */ private static final String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; /** * JAXP attribute value indicating the XSD schema language. */ private static final String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema"; private static final Log logger = LogFactory.getLog(DefaultDocumentLoader.class); /** * 使用標准的JAXP配置把InputSource加載為Document * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured * XML parser. */ public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { /* 利用給定的validationMode, namespaceAware;創建一個javax.xml.parsers.DocumentBuilderFactory的實例。 * 主要對驗證模式是XSD的處理 */ DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug("Using JAXP provider ["+ factory.getClass().getName() + "]"); } /* 利用創建的DocumentBuilderFactory和 給定的entityResolver、errorHandler構造 javax.xml.parsers.DocumentBuilder */ DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); /* 用得到的DocumentBuilder解析InputSource,返回Document */ return builder.parse(inputSource); } /** 創建一個 javax.xml.parsers.DocumentBuilderFactory的實例 * <p>主要對驗證模式是XSD的處理 * Create the {@link DocumentBuilderFactory} instance. * @param validationMode the type of validation: DTD or XSD * @param namespaceAware whether the returned factory is to provide support for XML namespaces * @return the JAXP DocumentBuilderFactory * @throws ParserConfigurationException if we failed to build a proper DocumentBuilderFactory */ protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(namespaceAware); if(validationMode != XmlValidationModeDetector.VALIDATION_NONE) { factory.setValidating(true); if(validationMode == XmlValidationModeDetector.VALIDATION_XSD) { // Enforce namespace aware for XSD...對XSD強制命名空間感知? factory.setNamespaceAware(true); try { factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE,XSD_SCHEMA_LANGUAGE); }catch (IllegalArgumentException ex) { ParserConfigurationException pcex = new ParserConfigurationException( "Unable to validate using XSD: Your JAXP provider [" + factory +"] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? "
+ "Upgrade to Apache Xerces (or Java 1.5) for full XSD support."); pcex.initCause(ex); throw pcex; } } } return factory; } /**創建一個JAXP的DocumentBuilder,這個bean定義閱讀器將用於解析xml文檔。 * 可以在子類中重寫,加入進一步的對builder的初始化。 * Create a JAXP DocumentBuilder that this bean definition reader * will use for parsing XML documents. Can be overridden in subclasses, * adding further initialization of the builder. * @param factory the JAXP DocumentBuilderFactory that the DocumentBuilder * should be created with * @param entityResolver the SAX EntityResolver to use * @param errorHandler the SAX ErrorHandler to use * @return the JAXP DocumentBuilder * @throws ParserConfigurationException if thrown by JAXP methods */ protected DocumentBuilder createDocumentBuilder( DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler) throws ParserConfigurationException { DocumentBuilder docBuilder = factory.newDocumentBuilder(); if (entityResolver != null) { docBuilder.setEntityResolver(entityResolver); } if (errorHandler != null) { docBuilder.setErrorHandler(errorHandler); } return docBuilder; } }
3.2.5 根據返回的Document注冊bean的信息
/** 注冊核心03:根據返回的Document注冊bean的信息。(重點,解析配置文件,然后注冊bean信息)
* (理解注冊、注入,lyn個人理解:
* 注冊:好比創建了一個登陸帳號,保存到了數據庫
* 注入:根據輸入的登陸信息,去數據庫找,找到就返回(把bean實例化)
*/
return registerBeanDefinitions(doc, resource);
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class; /** * Register the bean definitions contained in the given DOM document. * Called by {@code loadBeanDefinitions}. * <p>Creates a new instance of the parser class and invokes * {@code registerBeanDefinitions} on it. * @param doc the DOM document * @param resource the resource descriptor (for context information) * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of parsing errors * @see #loadBeanDefinitions * @see #setDocumentReaderClass * @see BeanDefinitionDocumentReader#registerBeanDefinitions */ @SuppressWarnings("deprecation") public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //org.springframework.beans.factory.xml.BeanDefinitionDocumentReader /* 使用DefaultBeanDefinitionDocumentReader實例化 BeanDefinitionDocumentReader(spring封裝接口)。 * 可通過XmlBeanDefinitionReader.setDocumentReaderClass(...)設置 */ BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); /* 設置環境變量 ,對profile來說不可能為null */ documentReader.setEnvironment(getEnvironment()); /* 獲取之前bean definition的加載數量 * getRegistry()->XmlBeanFactory extends DefaultListableBeanFactory */ int countBefore = getRegistry().getBeanDefinitionCount(); /* 核心 加載及注冊此次的bean definition*/ documentReader.registerBeanDefinitions(doc,createReaderContext(resource)); /* 返回本次加載的bean definition數量*/ return getRegistry().getBeanDefinitionCount() - countBefore; } /** 創建的BeanDefinitionDocumentReader用於實際從XML文檔中讀取bean定義。 * 默認實例指定的是“documentReaderClass”, * 可通過XmlBeanDefinitionReader.setDocumentReaderClass(...)設置 * Create the {@link BeanDefinitionDocumentReader} to use for actually * reading bean definitions from an XML document. * <p>The default implementation instantiates the specified "documentReaderClass". * @see #setDocumentReaderClass */ protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); } /** * Specify the BeanDefinitionDocumentReader implementation to use, * responsible for the actual reading of the XML bean definition document. * <p>The default is DefaultBeanDefinitionDocumentReader. * @param documentReaderClass the desired BeanDefinitionDocumentReader implementation class */ public void setDocumentReaderClass(Class<?> documentReaderClass) { if (documentReaderClass == null || !BeanDefinitionDocumentReader.class.isAssignableFrom(documentReaderClass)) { throw new IllegalArgumentException("documentReaderClass must be an implementation of the BeanDefinitionDocumentReader interface"); } this.documentReaderClass = documentReaderClass; } }
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { /** 注冊bean definition的核心。該方法提取Document中的org.w3c.dom.Element、及設置XmlReaderContext readerContext = XX; * 然后把提取的Element傳入核心的doRegisterBeanDefinitions(element),在進一部處理 * <p>此實現解析bean definition 根據"spring-beans" XSD(or DTD) * <p>This implementation parses bean definitions according to the "spring-beans" XSD * (or DTD, historically). * <p>打開一個DOM文檔,然后初始化在默認的指定的<beans/>中;最后解析包含的bean definition * <p>Opens a DOM Document; then initializes the default settings * specified at the {@code <beans/>} level; then parses the contained bean definitions. */ public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); /* ********核心注冊bean********* */ doRegisterBeanDefinitions(root); } /** 注冊的核心方法。 利用了模版方法模式 Template method。 * 注冊每個bean definition從給定的元素<beans/>中. * <p> 如果想在xml解析前后對Element元素做一些處理, * 則在DefaultBeanDefinitionDocumentReader的子類重寫preProcessXml(...)、postProcessXml(...)即可 * Register each bean definition within the given root {@code <beans/>} element. */ protected void doRegisterBeanDefinitions(Element root) { // 處理profile屬性 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } // 任何嵌套的<beans/> 都會在parseBeanDefinitions()中遞歸處理, // 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 parent = this.delegate; this.delegate = createDelegate(this.readerContext, root, parent); /** 利用了模版方法模式 Template method */ //解析xml前處理,默認是空實現,留給子類擴展 preProcessXml(root); //核心,把bean definition注冊到了 parseBeanDefinitions(root, this.delegate); //解析xml后處理,默認是空實現,留給子類擴展 postProcessXml(root); this.delegate = parent; } /** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */ protected void parseBeanDefinitions(Element root,BeanDefinitionParserDelegate delegate) { //對beans處理,默認的namespace if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; //對默認的元素標簽處理 如<bean id="b1" class="..."/> <alias/> <import/> if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate); } else {//對自定義元素標簽處理 如<tx:annotation-driven/> delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } /** * 處理默認元素標簽, <import/> <alias/> <bean/> <beans/> * @param ele * @param delegate */ private void parseDefaultElement(Element ele,BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse 如果是<beans/>則遞歸 doRegisterBeanDefinitions(ele); } } /** 處理給定的bean元素,並且解析bean definition和調用BeanDefinitionRegistry.registerBeanDefinition(...) 放到相應的ConcurrentHashMap中(線程安全,解決高並發、高吞吐的Map) * Process the given bean element, parsing the bean definition * and registering it with the registry. */ protected void processBeanDefinition(Element ele,BeanDefinitionParserDelegate delegate) { /* 利用BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element e) * 解析給定bean元素信息為 BeanDefinitionHolder ,這其中就包含了 id,class,alias,name等屬性 * */ BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // 若默認標簽的子節點下有 自定義屬性 , 還需要再次對自定義標簽進行解析 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // 最后調用 BeanDefinitionRegistry.registerBeanDefinition(...) 放到相應的ConcurrentHashMap中(線程安全,解決高並發、高吞吐的Map) BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. 發送注冊事件; // 通知相關的監聽器,這個bean已經注冊完成 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } } // createHelper留給子類重寫,但注解表明不推薦使用了; 模版方法模式 protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { BeanDefinitionParserDelegate delegate = createHelper(readerContext, root, parentDelegate); if (delegate == null) { delegate = new BeanDefinitionParserDelegate(readerContext, getEnvironment()); delegate.initDefaults(root, parentDelegate); } return delegate; } // 可以留給子類重寫 @Deprecated protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext,Element root, BeanDefinitionParserDelegate parentDelegate) { return null; } }

/** * Utility methods that are useful for bean definition reader implementations. Mainly intended for internal use. * @author Juergen Hoeller * @author Rob Harrop * @since 1.1 * @see PropertiesBeanDefinitionReader * @see org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader */ public class BeanDefinitionReaderUtils { /** * 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(); /** **最終的bean注冊,把bean definition保存到ConcurrentHashMap中** */ registry.registerBeanDefinition(beanName,definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } } } }
BeanDefinitionRegistry是個接口,spring用來統一管理bean definition的注冊。
在以上demo中,核心的一個方法是registerBeanDefinition(...).把bean definiton保存到ConcurrentHashMap中(線程安全,解決高並發、高吞吐的Map);
在spring給出的3個實現該方法的類中:
a) DefaultListableBeanFactory.class
b) GenericApplicationContext.class(調用就是a的實現)
c) SimpleBeanDefinitionRegistry.class
都是保存到ConcurrentHashMap中。DefaultListableBeanFactory.class相對於SimpleBeanDefinitionRegistry.class做了一些邏輯處理,且DefaultListableBeanFactory.class中提供了更多的信息,
比如:private final List<String> beanDefinitionNames = new ArrayList<String>(64); 保存了已注冊的bean-definition的beanNames。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { /** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64); /** List of bean definition names, in registration order */ private final List<String> beanDefinitionNames = new ArrayList<String>(64); /** Cached array of bean definition names in case of frozen configuration */ private String[] frozenBeanDefinitionNames; //--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry interface 實現bean definition的注冊 //--------------------------------------------------------------------- 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 oldBeanDefinition; synchronized (this.beanDefinitionMap) { oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!this.allowBeanDefinitionOverriding) { throw new BeanDefinitionStoreException( beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +"': There is already [" + oldBeanDefinition + "] bound."); } // 允許重復定義,logger信息(就的bean-definition被替換成新的) else { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName +"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } else { //新注冊bean-definition this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; } this.beanDefinitionMap.put(beanName, beanDefinition); } //處理允許重復bean-definition的情況 if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } } }

// 在GenericApplicationContext.class ->DefaultListableBeanFactory.class public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { private final DefaultListableBeanFactory beanFactory; //--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry //--------------------------------------------------------------------- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { this.beanFactory.registerBeanDefinition(beanName, beanDefinition); } }

public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry { /** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64); public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "'beanName' must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); this.beanDefinitionMap.put(beanName, beanDefinition); } }
3.2.6 什么是profile,其作用是什么?
3.3 獲取已注冊的bean,並注入. Demo0102Bean bean = (Demo0102Bean) factory.getBean("demo0102Bean");
此時,factory都是頂層BeanFactory.class的子類/實現類;
針對demo的例子,此時factory 是以XmlBeanFactory構造的:
DefaultListableBeanFactory:非抽象類
在demo中,factory.getBean("demo0102Bean"); –> getBean(...)是在BeanFactory接口中定義的,而在AbstractApplicationContext中實現.
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { /** Parent bean factory, for bean inheritance support(父級BeanFactory,為了支持bean的繼承)*/ private BeanFactory parentBeanFactory; /** ClassLoader to resolve bean class names with, if necessary(ClassLoader類加載器,當需要解析bean的類名時。)*/ private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); /** ClassLoader to temporarily resolve bean class names with, if necessary(臨時的ClassLoader,如果需要解析bean的類名時) */ private ClassLoader tempClassLoader; /** Whether to cache bean metadata or rather reobtain it for every access;每次訪問獲得的更精確的元數據,是否再次緩存。默認true */ private boolean cacheBeanMetadata = true; /** Resolution strategy for expressions in bean definition values */ private BeanExpressionResolver beanExpressionResolver; /** Spring ConversionService to use instead of PropertyEditors */ private ConversionService conversionService; /** Custom PropertyEditorRegistrars to apply to the beans of this factory */ private final Set<PropertyEditorRegistrar> propertyEditorRegistrars = new LinkedHashSet<PropertyEditorRegistrar>(4); /** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */ private TypeConverter typeConverter; /** Custom PropertyEditors to apply to the beans of this factory */ private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors = new HashMap<Class<?>, Class<? extends PropertyEditor>>(4); /** String resolvers to apply e.g. to annotation attribute values */ private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<StringValueResolver>(); /** BeanPostProcessors to apply in createBean */ private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>(); /** Indicates whether any InstantiationAwareBeanPostProcessors have been registered */ private boolean hasInstantiationAwareBeanPostProcessors; /** Indicates whether any DestructionAwareBeanPostProcessors have been registered */ private boolean hasDestructionAwareBeanPostProcessors; /** Map from scope identifier String to corresponding Scope */ private final Map<String, Scope> scopes = new HashMap<String, Scope>(8); /** Security context used when running with a SecurityManager */ private SecurityContextProvider securityContextProvider; /** Map from bean name to merged RootBeanDefinition:bean name -> RootBeanDefinition */ private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<String, RootBeanDefinition>(64); /** Names of beans that have already been created at least once(那些已經至少被創建過一次的beanName的ConcurrentHashMap) */ private final Map<String, Boolean> alreadyCreated = new ConcurrentHashMap<String, Boolean>(64); /** Names of beans that are currently in creation(當前正在創建的bean名稱,NamedThreadLocal<Object>)*/ private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal<Object>("Prototype beans currently in creation"); /** * Create a new AbstractBeanFactory. */ public AbstractBeanFactory() { } /** * Create a new AbstractBeanFactory with the given parent. * @param parentBeanFactory parent bean factory, or {@code null} if none * @see #getBean */ public AbstractBeanFactory(BeanFactory parentBeanFactory) { this.parentBeanFactory = parentBeanFactory; } //--------------------------------------------------------------------- // Implementation of BeanFactory interface BeanFactory接口的實現 //--------------------------------------------------------------------- public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); } /** * Return an instance, which may be shared or independent, of the specified bean. * @param name the name of the bean to retrieve * @param requiredType the required type of the bean to retrieve * @param args arguments to use if creating a prototype using explicit arguments to a * static factory method. It is invalid to use a non-null args value in any other case. * @return an instance of the bean * @throws BeansException if the bean could not be created */ public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException { return doGetBean(name, requiredType, args, false); } /** 返回指定bean的實例,其可以是共享 or 獨立的 * Return an instance, which may be shared or independent, of the specified bean. * @param name the name of the bean to retrieve ;bean的名稱檢索 * @param requiredType the required type of the bean to retrieve ; 需要注入的bean的類型檢索 * @param args arguments to use if creating a prototype using explicit arguments to a * static factory method. It is invalid to use a non-null args value in any other case. * @param typeCheckOnly whether the instance is obtained for a type check, * not for actual use * @return an instance of the bean * @throws BeansException if the bean could not be created */ @SuppressWarnings("unchecked") protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { // transformedBeanName(...) 返回真實的bean的名字 final String beanName = transformedBeanName(name); Object bean; //最后返回已注入的bean /* 要優先檢測緩存的原因: * 因為在創建單例bean的時候,可能存在依賴注入的情況。而在創建依賴的時候為了避免循環依賴, * spring的原則是不等bean創建完成就會將創建bean的ObjectFactory提早暴露出來。 * 也就是將ObjectFactory加入到緩存中,一旦當前bean創建時存在需要依賴另一個bean情況(這另一個bean可能在之前已創建過), * 則通過DefaultSingletonBeanRegistry.getSingleton(String beanName) 可以得到已創建的bean的sharedInstance。 * (在方法內部,也可能是找到了用於創建sharedInstance的ObjectFactory,再在方法內部用找到的ObjectFactory創建新sharedInstance加入緩存並返回) */ // Eagerly check singleton cache for manually registered singletons. 檢測緩存中是否有單例對象的bean實例 Object sharedInstance = getSingleton(beanName); //如果能從緩存中獲得已緩存的單例bean,並且參數args == null(只能在創建prototype時使用),那么直接返回緩存中的bean,否則繼續創建bean if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } //返回對應的實例,可能存在是FactoryBean的情況,返回的實際是通過FactoryBean創建的bean實例(如果beanName的命名是&開頭,那么返回的 Factorybean實例) bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //不能在緩存中找到單例bean /** 只有單例模式下,才會嘗試解決循環依賴。 原型模式下直接拋異常BeanCurrentlyInCreationException; * 什么是循環依賴:例如A中有B屬性,B中也有A屬性。但A還未創建完成時,會先去創建B,但創建B的時候B又要先去創建A,造成了循環依賴。 */ // Fail if we're already creating this bean instance: 失敗,如果我們已經創建了這個bean的實例 // We're assumably within a circular reference. 我們大概在循環引用 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. 檢測在當前factory是否存在對bean的定義。 BeanFactory parentBeanFactory = getParentBeanFactory(); /* 如果當前工廠AbstractBeanFactory存在父級BeanFactory, * 且當前AbstractBeanFactory不存在bean的定義(BeanDefinition),則把創建bean的職責交給父級Beanfactory */ if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); // 遞歸父類查找。 if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } if (!typeCheckOnly) { //是否是簡單的只做類型檢測,不只是類型檢測的話要加入緩存 // 把指定的beanName記錄到alreadyCreated map中(緩存),表明該beanName已經創建過,或即將創建(beanFactory用此來優化beanName重復創建) markBeanAsCreated(beanName); } try { //將存儲XML配置文件的GernericBeanDefinition轉換成RootBeanDefinition,如果指定的beanName是子bean的話,還會合並其父類的信息。 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { // 若存在依賴,則需要遞歸實例化依賴的bean。即A中有屬性B,B中有C,則遞歸先實例化C, 在實例話B 最后實例化A for (String dependsOnBean : dependsOn) { getBean(dependsOnBean); //遞歸 registerDependentBean(dependsOnBean, beanName);//緩存依賴調用 } } // Create bean instance. 依賴的bean實例化后,就可以創建bean自身的實例 if (mbd.isSingleton()) { //如果是singleton sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { public Object getObject() throws BeansException { try { //調用AbstractBeanFactory的實現類AbstractAutowireCapableBeanFactory中createBean方法 return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { //如果是prototype // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { //指定的scope上實例化bean String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { public Object getObject() throws BeansException { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; " + "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // 檢查需要的類型是否匹配實際的bean實例化類型 // Check if required type matches the type of the actual bean instance. if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type [" + ClassUtils.getQualifiedName(requiredType) + "]", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; } public boolean containsBean(String name) { String beanName = transformedBeanName(name); if (containsSingleton(beanName) || containsBeanDefinition(beanName)) { return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name)); } // Not found -> check parent. BeanFactory parentBeanFactory = getParentBeanFactory(); return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name))); } public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); Object beanInstance = getSingleton(beanName, false); if (beanInstance != null) { if (beanInstance instanceof FactoryBean) { return (BeanFactoryUtils.isFactoryDereference(name) || ((FactoryBean<?>) beanInstance).isSingleton()); } else { return !BeanFactoryUtils.isFactoryDereference(name); } } else if (containsSingleton(beanName)) { return true; } else { // No singleton instance found -> check bean definition. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // No bean definition found in this factory -> delegate to parent. return parentBeanFactory.isSingleton(originalBeanName(name)); } RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // In case of FactoryBean, return singleton status of created object if not a dereference. if (mbd.isSingleton()) { if (isFactoryBean(beanName, mbd)) { if (BeanFactoryUtils.isFactoryDereference(name)) { return true; } FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); return factoryBean.isSingleton(); } else { return !BeanFactoryUtils.isFactoryDereference(name); } } else { return false; } } } public boolean isPrototype(String name) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // No bean definition found in this factory -> delegate to parent. return parentBeanFactory.isPrototype(originalBeanName(name)); } RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); if (mbd.isPrototype()) { // In case of FactoryBean, return singleton status of created object if not a dereference. return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName, mbd)); } else { // Singleton or scoped - not a prototype. // However, FactoryBean may still produce a prototype object... if (BeanFactoryUtils.isFactoryDereference(name)) { return false; } if (isFactoryBean(beanName, mbd)) { final FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); if (System.getSecurityManager() != null) { return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { public Boolean run() { return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factoryBean).isPrototype()) || !factoryBean.isSingleton()); } }, getAccessControlContext()); } else { return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factoryBean).isPrototype()) || !factoryBean.isSingleton()); } } else { return false; } } } public boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); Class<?> typeToMatch = (targetType != null ? targetType : Object.class); // Check manually registered singletons. Object beanInstance = getSingleton(beanName, false); if (beanInstance != null) { if (beanInstance instanceof FactoryBean) { if (!BeanFactoryUtils.isFactoryDereference(name)) { Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance); return (type != null && ClassUtils.isAssignable(typeToMatch, type)); } else { return ClassUtils.isAssignableValue(typeToMatch, beanInstance); } } else { return !BeanFactoryUtils.isFactoryDereference(name) && ClassUtils.isAssignableValue(typeToMatch, beanInstance); } } else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) { // null instance registered return false; } else { // No singleton instance found -> check bean definition. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // No bean definition found in this factory -> delegate to parent. return parentBeanFactory.isTypeMatch(originalBeanName(name), targetType); } // Retrieve corresponding bean definition. RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); Class<?>[] typesToMatch = (FactoryBean.class.equals(typeToMatch) ? new Class<?>[] {typeToMatch} : new Class<?>[] {FactoryBean.class, typeToMatch}); // Check decorated bean definition, if any: We assume it'll be easier // to determine the decorated bean's type than the proxy's type. BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) { RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd); Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch); if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) { return typeToMatch.isAssignableFrom(targetClass); } } Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch); if (beanType == null) { return false; } // Check bean class whether we're dealing with a FactoryBean. if (FactoryBean.class.isAssignableFrom(beanType)) { if (!BeanFactoryUtils.isFactoryDereference(name)) { // If it's a FactoryBean, we want to look at what it creates, not the factory class. beanType = getTypeForFactoryBean(beanName, mbd); if (beanType == null) { return false; } } } else if (BeanFactoryUtils.isFactoryDereference(name)) { // Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean // type but we nevertheless are being asked to dereference a FactoryBean... // Let's check the original bean class and proceed with it if it is a FactoryBean. beanType = predictBeanType(beanName, mbd, FactoryBean.class); if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) { return false; } } return typeToMatch.isAssignableFrom(beanType); } } public Class<?> getType(String name) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); // Check manually registered singletons. Object beanInstance = getSingleton(beanName, false); if (beanInstance != null) { if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) { return getTypeForFactoryBean((FactoryBean<?>) beanInstance); } else { return beanInstance.getClass(); } } else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) { // null instance registered return null; } else { // No singleton instance found -> check bean definition. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // No bean definition found in this factory -> delegate to parent. return parentBeanFactory.getType(originalBeanName(name)); } RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // Check decorated bean definition, if any: We assume it'll be easier // to determine the decorated bean's type than the proxy's type. BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) { RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd); Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd); if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) { return targetClass; } } Class<?> beanClass = predictBeanType(beanName, mbd); // Check bean class whether we're dealing with a FactoryBean. if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) { if (!BeanFactoryUtils.isFactoryDereference(name)) { // If it's a FactoryBean, we want to look at what it creates, not at the factory class. return getTypeForFactoryBean(beanName, mbd); } else { return beanClass; } } else { return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null); } } } @Override public String[] getAliases(String name) { String beanName = transformedBeanName(name); List<String> aliases = new ArrayList<String>(); boolean factoryPrefix = name.startsWith(FACTORY_BEAN_PREFIX); String fullBeanName = beanName; if (factoryPrefix) { fullBeanName = FACTORY_BEAN_PREFIX + beanName; } if (!fullBeanName.equals(name)) { aliases.add(fullBeanName); } String[] retrievedAliases = super.getAliases(beanName); for (String retrievedAlias : retrievedAliases) { String alias = (factoryPrefix ? FACTORY_BEAN_PREFIX : "") + retrievedAlias; if (!alias.equals(name)) { aliases.add(alias); } } if (!containsSingleton(beanName) && !containsBeanDefinition(beanName)) { BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null) { aliases.addAll(Arrays.asList(parentBeanFactory.getAliases(fullBeanName))); } } return StringUtils.toStringArray(aliases); } //--------------------------------------------------------------------- // Implementation of HierarchicalBeanFactory interface 實現接口HierarchicalBeanFactory的方法 //--------------------------------------------------------------------- /** * Return the parent bean factory, or null if there is none. */ public BeanFactory getParentBeanFactory() { return this.parentBeanFactory; } public boolean containsLocalBean(String name) { String beanName = transformedBeanName(name); return ((containsSingleton(beanName) || containsBeanDefinition(beanName)) && (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName))); } //--------------------------------------------------------------------- // Implementation of ConfigurableBeanFactory interface //--------------------------------------------------------------------- public void setParentBeanFactory(BeanFactory parentBeanFactory) { if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) { throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory); } this.parentBeanFactory = parentBeanFactory; } public void setBeanClassLoader(ClassLoader beanClassLoader) { this.beanClassLoader = (beanClassLoader != null ? beanClassLoader : ClassUtils.getDefaultClassLoader()); } public ClassLoader getBeanClassLoader() { return this.beanClassLoader; } public void setTempClassLoader(ClassLoader tempClassLoader) { this.tempClassLoader = tempClassLoader; } public ClassLoader getTempClassLoader() { return this.tempClassLoader; } public void setCacheBeanMetadata(boolean cacheBeanMetadata) { this.cacheBeanMetadata = cacheBeanMetadata; } public boolean isCacheBeanMetadata() { return this.cacheBeanMetadata; } public void setBeanExpressionResolver(BeanExpressionResolver resolver) { this.beanExpressionResolver = resolver; } public BeanExpressionResolver getBeanExpressionResolver() { return this.beanExpressionResolver; } public void setConversionService(ConversionService conversionService) { this.conversionService = conversionService; } public ConversionService getConversionService() { return this.conversionService; } public void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar) { Assert.notNull(registrar, "PropertyEditorRegistrar must not be null"); this.propertyEditorRegistrars.add(registrar); } /** * Return the set of PropertyEditorRegistrars. */ public Set<PropertyEditorRegistrar> getPropertyEditorRegistrars() { return this.propertyEditorRegistrars; } public void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass) { Assert.notNull(requiredType, "Required type must not be null"); Assert.isAssignable(PropertyEditor.class, propertyEditorClass); this.customEditors.put(requiredType, propertyEditorClass); } public void copyRegisteredEditorsTo(PropertyEditorRegistry registry) { registerCustomEditors(registry); } /** * Return the map of custom editors, with Classes as keys and PropertyEditor classes as values. */ public Map<Class<?>, Class<? extends PropertyEditor>> getCustomEditors() { return this.customEditors; } public void setTypeConverter(TypeConverter typeConverter) { this.typeConverter = typeConverter; } /** * Return the custom TypeConverter to use, if any. * @return the custom TypeConverter, or {@code null} if none specified */ protected TypeConverter getCustomTypeConverter() { return this.typeConverter; } public TypeConverter getTypeConverter() { TypeConverter customConverter = getCustomTypeConverter(); if (customConverter != null) { return customConverter; } else { // Build default TypeConverter, registering custom editors. SimpleTypeConverter typeConverter = new SimpleTypeConverter(); typeConverter.setConversionService(getConversionService()); registerCustomEditors(typeConverter); return typeConverter; } } public void addEmbeddedValueResolver(StringValueResolver valueResolver) { Assert.notNull(valueResolver, "StringValueResolver must not be null"); this.embeddedValueResolvers.add(valueResolver); } public String resolveEmbeddedValue(String value) { String result = value; for (StringValueResolver resolver : this.embeddedValueResolvers) { if (result == null) { return null; } result = resolver.resolveStringValue(result); } return result; } public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) { Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null"); this.beanPostProcessors.remove(beanPostProcessor); this.beanPostProcessors.add(beanPostProcessor); if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) { this.hasInstantiationAwareBeanPostProcessors = true; } if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) { this.hasDestructionAwareBeanPostProcessors = true; } } public int getBeanPostProcessorCount() { return this.beanPostProcessors.size(); } /** * Return the list of BeanPostProcessors that will get applied * to beans created with this factory. */ public List<BeanPostProcessor> getBeanPostProcessors() { return this.beanPostProcessors; } /** * Return whether this factory holds a InstantiationAwareBeanPostProcessor * that will get applied to singleton beans on shutdown. * @see #addBeanPostProcessor * @see org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor */ protected boolean hasInstantiationAwareBeanPostProcessors() { return this.hasInstantiationAwareBeanPostProcessors; } /** * Return whether this factory holds a DestructionAwareBeanPostProcessor * that will get applied to singleton beans on shutdown. * @see #addBeanPostProcessor * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor */ protected boolean hasDestructionAwareBeanPostProcessors() { return this.hasDestructionAwareBeanPostProcessors; } public void registerScope(String scopeName, Scope scope) { Assert.notNull(scopeName, "Scope identifier must not be null"); Assert.notNull(scope, "Scope must not be null"); if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) { throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'"); } this.scopes.put(scopeName, scope); } public String[] getRegisteredScopeNames() { return StringUtils.toStringArray(this.scopes.keySet()); } public Scope getRegisteredScope(String scopeName) { Assert.notNull(scopeName, "Scope identifier must not be null"); return this.scopes.get(scopeName); } /** * Set the security context provider for this bean factory. If a security manager * is set, interaction with the user code will be executed using the privileged * of the provided security context. */ public void setSecurityContextProvider(SecurityContextProvider securityProvider) { this.securityContextProvider = securityProvider; } /** * Delegate the creation of the access control context to the * {@link #setSecurityContextProvider SecurityContextProvider}. */ @Override public AccessControlContext getAccessControlContext() { return (this.securityContextProvider != null ? this.securityContextProvider.getAccessControlContext() : AccessController.getContext()); } public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) { Assert.notNull(otherFactory, "BeanFactory must not be null"); setBeanClassLoader(otherFactory.getBeanClassLoader()); setCacheBeanMetadata(otherFactory.isCacheBeanMetadata()); setBeanExpressionResolver(otherFactory.getBeanExpressionResolver()); if (otherFactory instanceof AbstractBeanFactory) { AbstractBeanFactory otherAbstractFactory = (AbstractBeanFactory) otherFactory; this.customEditors.putAll(otherAbstractFactory.customEditors); this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars); this.beanPostProcessors.addAll(otherAbstractFactory.beanPostProcessors); this.hasInstantiationAwareBeanPostProcessors = this.hasInstantiationAwareBeanPostProcessors || otherAbstractFactory.hasInstantiationAwareBeanPostProcessors; this.hasDestructionAwareBeanPostProcessors = this.hasDestructionAwareBeanPostProcessors || otherAbstractFactory.hasDestructionAwareBeanPostProcessors; this.scopes.putAll(otherAbstractFactory.scopes); this.securityContextProvider = otherAbstractFactory.securityContextProvider; } else { setTypeConverter(otherFactory.getTypeConverter()); } } /** * Return a 'merged' BeanDefinition for the given bean name, * merging a child bean definition with its parent if necessary. * <p>This {@code getMergedBeanDefinition} considers bean definition * in ancestors as well. * @param name the name of the bean to retrieve the merged definition for * (may be an alias) * @return a (potentially merged) RootBeanDefinition for the given bean * @throws NoSuchBeanDefinitionException if there is no bean with the given name * @throws BeanDefinitionStoreException in case of an invalid bean definition */ public BeanDefinition getMergedBeanDefinition(String name) throws BeansException { String beanName = transformedBeanName(name); // Efficiently check whether bean definition exists in this factory. if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) { return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName); } // Resolve merged bean definition locally. return getMergedLocalBeanDefinition(beanName); } public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); Object beanInstance = getSingleton(beanName, false); if (beanInstance != null) { return (beanInstance instanceof FactoryBean); } else if (containsSingleton(beanName)) { // null instance registered return false; } // No singleton instance found -> check bean definition. if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) { // No bean definition found in this factory -> delegate to parent. return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name); } return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName)); } @Override public boolean isActuallyInCreation(String beanName) { return isSingletonCurrentlyInCreation(beanName) || isPrototypeCurrentlyInCreation(beanName); } /** 返回指定bean原型當前是否處於正在創建(當前線程內) * Return whether the specified prototype bean is currently in creation * (within the current thread). * @param beanName the name of the bean */ protected boolean isPrototypeCurrentlyInCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))); } /** * Callback before prototype creation. * <p>The default implementation register the prototype as currently in creation. * @param beanName the name of the prototype about to be created * @see #isPrototypeCurrentlyInCreation */ @SuppressWarnings("unchecked") protected void beforePrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal == null) { this.prototypesCurrentlyInCreation.set(beanName); } else if (curVal instanceof String) { Set<String> beanNameSet = new HashSet<String>(2); beanNameSet.add((String) curVal); beanNameSet.add(beanName); this.prototypesCurrentlyInCreation.set(beanNameSet); } else { Set<String> beanNameSet = (Set<String>) curVal; beanNameSet.add(beanName); } } /** * Callback after prototype creation. * <p>The default implementation marks the prototype as not in creation anymore. * @param beanName the name of the prototype that has been created * @see #isPrototypeCurrentlyInCreation */ @SuppressWarnings("unchecked") protected void afterPrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal instanceof String) { this.prototypesCurrentlyInCreation.remove(); } else if (curVal instanceof Set) { Set<String> beanNameSet = (Set<String>) curVal; beanNameSet.remove(beanName); if (beanNameSet.isEmpty()) { this.prototypesCurrentlyInCreation.remove(); } } } public void destroyBean(String beanName, Object beanInstance) { destroyBean(beanName, beanInstance, getMergedLocalBeanDefinition(beanName)); } /** * Destroy the given bean instance (usually a prototype instance * obtained from this factory) according to the given bean definition. * @param beanName the name of the bean definition * @param beanInstance the bean instance to destroy * @param mbd the merged bean definition */ protected void destroyBean(String beanName, Object beanInstance, RootBeanDefinition mbd) { new DisposableBeanAdapter(beanInstance, beanName, mbd, getBeanPostProcessors(), getAccessControlContext()).destroy(); } public void destroyScopedBean(String beanName) { RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); if (mbd.isSingleton() || mbd.isPrototype()) { throw new IllegalArgumentException( "Bean name '" + beanName + "' does not correspond to an object in a mutable scope"); } String scopeName = mbd.getScope(); Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope SPI registered for scope '" + scopeName + "'"); } Object bean = scope.remove(beanName); if (bean != null) { destroyBean(beanName, bean, mbd); } } //--------------------------------------------------------------------- // Implementation methods //--------------------------------------------------------------------- /** 返回bean的名字, * Return the bean name, stripping out(剔除) the factory dereference prefix(前綴) if necessary, * and resolving aliases to canonical names.解決別名規范名稱 * @param name the user-specified name * @return the transformed bean name */ protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); } /** * Determine the original bean name, resolving locally defined aliases to canonical names. * @param name the user-specified name * @return the original bean name */ protected String originalBeanName(String name) { String beanName = transformedBeanName(name); if (name.startsWith(FACTORY_BEAN_PREFIX)) { beanName = FACTORY_BEAN_PREFIX + beanName; } return beanName; } /** * Initialize the given BeanWrapper with the custom editors registered * with this factory. To be called for BeanWrappers that will create * and populate bean instances. * <p>The default implementation delegates to {@link #registerCustomEditors}. * Can be overridden in subclasses. * @param bw the BeanWrapper to initialize */ protected void initBeanWrapper(BeanWrapper bw) { bw.setConversionService(getConversionService()); registerCustomEditors(bw); } /** * Initialize the given PropertyEditorRegistry with the custom editors * that have been registered with this BeanFactory. * <p>To be called for BeanWrappers that will create and populate bean * instances, and for SimpleTypeConverter used for constructor argument * and factory method type conversion. * @param registry the PropertyEditorRegistry to initialize */ protected void registerCustomEditors(PropertyEditorRegistry registry) { PropertyEditorRegistrySupport registrySupport = (registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null); if (registrySupport != null) { registrySupport.useConfigValueEditors(); } if (!this.propertyEditorRegistrars.isEmpty()) { for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) { try { registrar.registerCustomEditors(registry); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; if (isCurrentlyInCreation(bce.getBeanName())) { if (logger.isDebugEnabled()) { logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() + "] failed because it tried to obtain currently created bean '" + ex.getBeanName() + "': " + ex.getMessage()); } onSuppressedException(ex); continue; } } throw ex; } } } if (!this.customEditors.isEmpty()) { for (Map.Entry<Class<?>, Class<? extends PropertyEditor>> entry : this.customEditors.entrySet()) { Class<?> requiredType = entry.getKey(); Class<? extends PropertyEditor> editorClass = entry.getValue(); registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)); } } } /** 返回一個合並RootBeanDefinition,將存儲XML配置文件的GernericBeanDefinition轉換成RootBeanDefinition,如果指定的beanName是子bean的話,還會合並其父類的信息。 * <p>Return a merged RootBeanDefinition, traversing the parent bean definition * if the specified bean corresponds to a child bean definition. * @param beanName the name of the bean to retrieve the merged definition for * @return a (potentially merged) RootBeanDefinition for the given bean * @throws NoSuchBeanDefinitionException if there is no bean with the given name * @throws BeanDefinitionStoreException in case of an invalid bean definition */ protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException { // Quick check on the concurrent map first, with minimal locking. 快速檢查並發映射,以最小的鎖定(此小鎖中的map所包含的key可能不存在,但全鎖可能存在,所以后面還有全鎖檢測) RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName); if (mbd != null) { return mbd; } return getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); } /** * Return a RootBeanDefinition for the given top-level bean, by merging with * the parent if the given bean's definition is a child bean definition. * @param beanName the name of the bean definition * @param bd the original bean definition (Root/ChildBeanDefinition) * @return a (potentially merged) RootBeanDefinition for the given bean * @throws BeanDefinitionStoreException in case of an invalid bean definition */ protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd) throws BeanDefinitionStoreException { return getMergedBeanDefinition(beanName, bd, null); } /** * Return a RootBeanDefinition for the given bean, by merging with the * parent if the given bean's definition is a child bean definition. * @param beanName the name of the bean definition * @param bd the original bean definition (Root/ChildBeanDefinition) * @param containingBd the containing bean definition in case of inner bean, * or {@code null} in case of a top-level bean * @return a (potentially merged) RootBeanDefinition for the given bean * @throws BeanDefinitionStoreException in case of an invalid bean definition */ protected RootBeanDefinition getMergedBeanDefinition( String beanName, BeanDefinition bd, BeanDefinition containingBd) throws BeanDefinitionStoreException { synchronized (this.mergedBeanDefinitions) { RootBeanDefinition mbd = null; // Check with full lock now in order to enforce the same merged instance. if (containingBd == null) { //全鎖檢測是否已存在了 已合並的 相同beanName; (ConcurrentHashMap分離鎖特性,前面用最小的鎖檢測過,但可能別的線程/鎖 進行了合並,所以要再次用全鎖檢測。) mbd = this.mergedBeanDefinitions.get(beanName); } if (mbd == null) { //if判斷是否需要合並 父類的bean-definiton if (bd.getParentName() == null) { //不存在父類的bean-definition // Use copy of given root bean definition. if (bd instanceof RootBeanDefinition) { mbd = ((RootBeanDefinition) bd).cloneBeanDefinition(); } else { mbd = new RootBeanDefinition(bd); } } else { //需要合並父類的bean-definition // Child bean definition: needs to be merged with parent. BeanDefinition pbd; try { String parentBeanName = transformedBeanName(bd.getParentName()); if (!beanName.equals(parentBeanName)) { pbd = getMergedBeanDefinition(parentBeanName); } else { if (getParentBeanFactory() instanceof ConfigurableBeanFactory) { pbd = ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(parentBeanName); } else { throw new NoSuchBeanDefinitionException(bd.getParentName(), "Parent name '" + bd.getParentName() + "' is equal to bean name '" + beanName + "': cannot be resolved without an AbstractBeanFactory parent"); } } } catch (NoSuchBeanDefinitionException ex) { throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName, "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex); } // Deep copy with overridden values. mbd = new RootBeanDefinition(pbd); mbd.overrideFrom(bd); } // Set default singleton scope, if not configured before. 設置默認為單例模式 if (!StringUtils.hasLength(mbd.getScope())) { mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON); } // 一個包含了非單例的bean,其本身不可能是單例; 則把指定的beanName的bean-definiton的scope指定為 containingBd.getScope() // A bean contained in a non-singleton bean cannot be a singleton itself. // Let's correct(糾正) this on the fly here, since this might be the result of // parent-child merging for the outer bean, in which case the original inner bean // definition will not have inherited the merged outer bean's singleton status. /** if判斷,當指定beanName包含一個非單例的bean,且beanName自身是單例,則把beanName的scope糾正為其包含的bean的scope*/ if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) { mbd.setScope(containingBd.getScope()); } // Only cache the merged bean definition if we're already about to create an // instance of the bean, or at least have already created an instance before. /** 只是緩存一個合並后的bean-definiton,如果我們已創建了這個beanName的實例,或者至少在之前已經創建過 。 * (把當前指定beanName的bean-definiton存到mergedBeanDefinitions map中做緩存) * isCacheBeanMetadata():每次訪問獲得的更精確的元數據,是否再次緩存。默認true * isBeanEligibleForMetadataCaching(beanName): 確定指定的beanName是否有資格對 其bean-definition元數據進行緩存 */ if (containingBd == null && isCacheBeanMetadata() && isBeanEligibleForMetadataCaching(beanName)) { this.mergedBeanDefinitions.put(beanName, mbd); } } return mbd; } } /** 校驗給定的 merged-bean-definition, * Check the given merged bean definition, * potentially throwing validation exceptions. * @param mbd the merged bean definition to check * @param beanName the name of the bean * @param args the arguments for bean creation, if any * @throws BeanDefinitionStoreException in case of validation failure */ protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, Object[] args) throws BeanDefinitionStoreException { // check if bean definition is not abstract if (mbd.isAbstract()) { throw new BeanIsAbstractException(beanName); } // Check validity of the usage of the args parameter. This can // only be used for prototypes constructed via a factory method. if (args != null && !mbd.isPrototype()) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "Can only specify arguments for the getBean method when referring to a prototype bean definition"); } } /** * Remove the merged bean definition for the specified bean, * recreating it on next access. * @param beanName the bean name to clear the merged definition for */ protected void clearMergedBeanDefinition(String beanName) { this.mergedBeanDefinitions.remove(beanName); } /** 根據RootBeanDefinition中設定的beanClass信息來解析bean,得到其Class<?> * Resolve the bean class for the specified bean definition, * resolving a bean class name into a Class reference (if necessary) * and storing the resolved Class in the bean definition for further use. * @param mbd the merged bean definition to determine the class for * @param beanName the name of the bean (for error handling purposes) * @param typesToMatch the types to match in case of internal type matching purposes * (also signals that the returned {@code Class} will never be exposed to application code) * @return the resolved bean class (or {@code null} if none) * @throws CannotLoadBeanClassException if we failed to load the class */ protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch) throws CannotLoadBeanClassException { try { if (mbd.hasBeanClass()) { return mbd.getBeanClass(); } if (System.getSecurityManager() != null) { //權限驗證 return AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() { public Class<?> run() throws Exception { return doResolveBeanClass(mbd, typesToMatch); } }, getAccessControlContext()); } else { return doResolveBeanClass(mbd, typesToMatch); } } catch (PrivilegedActionException pae) { ClassNotFoundException ex = (ClassNotFoundException) pae.getException(); throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex); } catch (ClassNotFoundException ex) { throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex); } catch (LinkageError err) { throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err); } } /** * 如果typesToMatch !=null,則會嘗試用this.tempClassLoader臨時類加載器,去解析bean得到其類;<br> * 否則,用this.beanClassLoader,去解析bean得到其類; <b>都可能返回null</b> * @param mbd * @param typesToMatch * @return 根據bean解析得到的Class<?> * @throws ClassNotFoundException */ private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException { if (!ObjectUtils.isEmpty(typesToMatch)) { //當類型匹配不是null時,嘗試用tempClassLoader 臨時類加載器去解析bean得到其類 ClassLoader tempClassLoader = getTempClassLoader(); if (tempClassLoader != null) { if (tempClassLoader instanceof DecoratingClassLoader) { DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader; for (Class<?> typeToMatch : typesToMatch) { dcl.excludeClass(typeToMatch.getName()); } } String className = mbd.getBeanClassName(); return (className != null ? ClassUtils.forName(className, tempClassLoader) : null); } } return mbd.resolveBeanClass(getBeanClassLoader()); //用bean的類加載器去解析bean得到其類 } /** * Evaluate the given String as contained in a bean definition, * potentially resolving it as an expression. * @param value the value to check * @param beanDefinition the bean definition that the value comes from * @return the resolved value * @see #setBeanExpressionResolver */ protected Object evaluateBeanDefinitionString(String value, BeanDefinition beanDefinition) { if (this.beanExpressionResolver == null) { return value; } Scope scope = (beanDefinition != null ? getRegisteredScope(beanDefinition.getScope()) : null); return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope)); } /** * Predict the eventual bean type (of the processed bean instance) for the * specified bean. Called by {@link #getType} and {@link #isTypeMatch}. * Does not need to handle FactoryBeans specifically, since it is only * supposed to operate on the raw bean type. * <p>This implementation is simplistic in that it is not able to * handle factory methods and InstantiationAwareBeanPostProcessors. * It only predicts the bean type correctly for a standard bean. * To be overridden in subclasses, applying more sophisticated type detection. * @param beanName the name of the bean * @param mbd the merged bean definition to determine the type for * @param typesToMatch the types to match in case of internal type matching purposes * (also signals that the returned {@code Class} will never be exposed to application code) * @return the type of the bean, or {@code null} if not predictable */ protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) { if (mbd.getFactoryMethodName() != null) { return null; } return resolveBeanClass(mbd, beanName, typesToMatch); } /** * Check whether the given bean is defined as a {@link FactoryBean}. * @param beanName the name of the bean * @param mbd the corresponding bean definition */ protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) { Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class); return (beanType != null && FactoryBean.class.isAssignableFrom(beanType)); } /** * Determine the bean type for the given FactoryBean definition, as far as possible. * Only called if there is no singleton instance registered for the target bean already. * <p>The default implementation creates the FactoryBean via {@code getBean} * to call its {@code getObjectType} method. Subclasses are encouraged to optimize * this, typically by just instantiating the FactoryBean but not populating it yet, * trying whether its {@code getObjectType} method already returns a type. * If no type found, a full FactoryBean creation as performed by this implementation * should be used as fallback. * @param beanName the name of the bean * @param mbd the merged bean definition for the bean * @return the type for the bean if determinable, or {@code null} else * @see org.springframework.beans.factory.FactoryBean#getObjectType() * @see #getBean(String) */ protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) { if (!mbd.isSingleton()) { return null; } try { FactoryBean<?> factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true); return getTypeForFactoryBean(factoryBean); } catch (BeanCreationException ex) { // Can only happen when getting a FactoryBean. if (logger.isDebugEnabled()) { logger.debug("Ignoring bean creation exception on FactoryBean type check: " + ex); } onSuppressedException(ex); return null; } } /** 標記指定的beanName為已創建(或即將創建);這容許讓beanFactory對重復創建的beanName做緩存優化 * Mark the specified bean as already created (or about to be created). * <p>This allows the bean factory to optimize its caching for repeated * creation of the specified bean. * @param beanName the name of the bean */ protected void markBeanAsCreated(String beanName) { if (!this.alreadyCreated.containsKey(beanName)) { this.alreadyCreated.put(beanName, Boolean.TRUE); } } /** * Perform appropriate cleanup of cached metadata after bean creation failed. * @param beanName the name of the bean */ protected void cleanupAfterBeanCreationFailure(String beanName) { this.alreadyCreated.remove(beanName); } /** 確定指定的beanName是否有資格對 其bean-definition元數據進行緩存。(如果alreadyCreated map中包含此beanName,返回true) * <p>Determine whether the specified bean is eligible for having * its bean definition metadata cached. * @param beanName the name of the bean * @return {@code true} if the bean's metadata may be cached * at this point already */ protected boolean isBeanEligibleForMetadataCaching(String beanName) { return this.alreadyCreated.containsKey(beanName); } /** * Remove the singleton instance (if any) for the given bean name, * but only if it hasn't been used for other purposes than type checking. * @param beanName the name of the bean * @return {@code true} if actually removed, {@code false} otherwise */ protected boolean removeSingletonIfCreatedForTypeCheckOnly(String beanName) { if (!this.alreadyCreated.containsKey(beanName)) { removeSingleton(beanName); return true; } else { return false; } } /** 獲取給定bean的實例化對象,無論是bean實例本身 或 是在FactoryBean下生成的bean<BR> * (主要是beanName是否以&開頭,是則返回FactoryBean;否則返回FactoryBean創建的bean實例)<p> * Get the object for the given bean instance, either the bean * instance itself or its created object in case of a FactoryBean. * @param beanInstance the shared bean instance * @param name name that may include factory dereference prefix * @param beanName the canonical bean name * @param mbd the merged bean definition * @return the object to expose for the bean */ protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { // Don't let calling code try to dereference the factory if the bean isn't a factory. if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); } /* 現在我們已經有了一個bean的實例化(即參數傳入的beanInstance),它可能普通的bean,也可能是FactoryBean。 * 如果它是FactoryBean,我們就用這個FactoryBean創建一個新的bean實例化對象返回, * 除非調用者想要的就是一個factory的引用,(即使beanInstance是FactoryBean,但也可以通過beanName的命名來返回FactoryBean,而非FactoryBean創建的bean。 * 強制返回本身的實例beanInstance,這beanName以"&"開頭。 BeanFactoryUtils.isFactoryDereference(name)中判斷的返回true ) */ // Now we have the bean instance, which may be a normal bean or a FactoryBean. // If it's a FactoryBean, we use it to create a bean instance, unless the // caller actually wants a reference to the factory. if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; //如果不是FactoryBean的情況,返回其本身的bean實例化對象 } // 當beanInstance是FactoryBean,且beanName不是以"&"開頭,即要返回的是通過FactoryBean創建的bean對象實例 Object object = null; if (mbd == null) { // 先從緩存中獲取 object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // Return bean instance from factory. 到此,beanInstance一定是FactoryBean,進行Object -> FactoryBean的類型轉換 FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // Caches object obtained from FactoryBean if it is a singleton. // containsBeanDefinition(...) 檢測beanDefinitionMap中(即所有已加載的類中)是否已定義了beanName if (mbd == null && containsBeanDefinition(beanName)) { //已定義beanName mbd = getMergedLocalBeanDefinition(beanName); } //是否是用戶定義的而不是程序自身定義 boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } /** * Determine whether the given bean name is already in use within this factory, * i.e. whether there is a local bean or alias registered under this name or * an inner bean created with this name. * @param beanName the name to check */ public boolean isBeanNameInUse(String beanName) { return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName); } /** * Determine whether the given bean requires destruction on shutdown. * <p>The default implementation checks the DisposableBean interface as well as * a specified destroy method and registered DestructionAwareBeanPostProcessors. * @param bean the bean instance to check * @param mbd the corresponding bean definition * @see org.springframework.beans.factory.DisposableBean * @see AbstractBeanDefinition#getDestroyMethodName() * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor */ protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) { return (bean != null && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || hasDestructionAwareBeanPostProcessors())); } /** * Add the given bean to the list of disposable beans in this factory, * registering its DisposableBean interface and/or the given destroy method * to be called on factory shutdown (if applicable). Only applies to singletons. * @param beanName the name of the bean * @param bean the bean instance * @param mbd the bean definition for the bean * @see RootBeanDefinition#isSingleton * @see RootBeanDefinition#getDependsOn * @see #registerDisposableBean * @see #registerDependentBean */ protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) { AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null); if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) { if (mbd.isSingleton()) { // Register a DisposableBean implementation that performs all destruction // work for the given bean: DestructionAwareBeanPostProcessors, // DisposableBean interface, custom destroy method. registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc)); } else { // A bean with a custom scope... Scope scope = this.scopes.get(mbd.getScope()); if (scope == null) { throw new IllegalStateException("No Scope registered for scope '" + mbd.getScope() + "'"); } scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc)); } } } //--------------------------------------------------------------------- // Abstract methods to be implemented by subclasses //--------------------------------------------------------------------- /** * Check if this bean factory contains a bean definition with the given name. * Does not consider any hierarchy this factory may participate in. * Invoked by {@code containsBean} when no cached singleton instance is found. * <p>Depending on the nature of the concrete bean factory implementation, * this operation might be expensive (for example, because of directory lookups * in external registries). However, for listable bean factories, this usually * just amounts to a local hash lookup: The operation is therefore part of the * public interface there. The same implementation can serve for both this * template method(模版方法設計模式) and the public interface method in that case. * @param beanName the name of the bean to look for * @return if this bean factory contains a bean definition with the given name * @see #containsBean * @see org.springframework.beans.factory.ListableBeanFactory#containsBeanDefinition */ protected abstract boolean containsBeanDefinition(String beanName); /** * Return the bean definition for the given bean name. * Subclasses should normally implement caching, as this method is invoked * by this class every time bean definition metadata is needed. * <p>Depending on the nature of the concrete bean factory implementation, * this operation might be expensive (for example, because of directory lookups * in external registries). However, for listable bean factories, this usually * just amounts to a local hash lookup: The operation is therefore part of the * public interface there. The same implementation can serve for both this * template method and the public interface method in that case. * @param beanName the name of the bean to find a definition for * @return the BeanDefinition for this prototype name (never {@code null}) * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException * if the bean definition cannot be resolved * @throws BeansException in case of errors * @see RootBeanDefinition * @see ChildBeanDefinition * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition */ protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException; /** * Create a bean instance for the given bean definition. * The bean definition will already have been merged with the parent * definition in case of a child definition. * <p>All the other methods in this class invoke this method, although * beans may be cached after being instantiated by this method. All bean * instantiation within this class is performed by this method. * @param beanName the name of the bean * @param mbd the merged bean definition for the bean * @param args arguments to use if creating a prototype using explicit arguments to a * static factory method. This parameter must be {@code null} except in this case. * @return a new instance of the bean * @throws BeanCreationException if the bean could not be created */ protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException; }
四、總結心得
(太晚了,明早睡起來寫…)
隔一晚上都不知道要寫什么了,也不想寫了。現在通過看源碼主要的不是想知道其是如何實現,現階段更想學到的是通過好的源碼學習編碼風格、命名、及部分代碼該怎么寫(比如exception)