javascript
深入理解 Spring 之源码剖析IOC
推薦兩篇文章:
https://www.jianshu.com/p/e4ca039a2272
https://www.cnblogs.com/ITtangtang/p/3978349.html
一、介紹
作為Java程序員,Spirng我們再熟悉不過,可以說比自己的女朋友還要親密,每天都會和他在一起,然而我們真的了解spring嗎?
我們都知道,Spring的核心是IOC和AOP,但樓主認(rèn)為,如果從這兩個核心中挑選一個更重要的,那非IOC莫屬。AOP 也是依賴于IOC,從某些角度講,AOP就是IOC的一個擴(kuò)展功能。
什么是IOC? IOC解決了什么問題?IOC的原理是什么?Spring的IOC是怎么實(shí)現(xiàn)的?今天我們將會將這幾個問題一起解決。
1. 什么是IOC?
控制反轉(zhuǎn)(Inversion of Control,縮寫為IoC),是面向?qū)ο缶幊讨械囊环N設(shè)計(jì)原則,可以用來減低計(jì)算機(jī)代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。通過控制反轉(zhuǎn),對象在被創(chuàng)建的時候,由一個調(diào)控系統(tǒng)內(nèi)所有對象的外界實(shí)體,將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。
2. IOC 解決了什么問題?
簡單來說, IOC 解決了類與類之間的依賴關(guān)系。程序員將控制類與類之間依賴的權(quán)利交給了IOC,即:控制被反轉(zhuǎn)了。
3. IOC 的原理是什么?
其實(shí) IOC 的原理很簡單,底層就是java的反射。給定一個字符串能創(chuàng)建一個實(shí)例,利用set方法對實(shí)例的依賴進(jìn)行注入。
4. Spring的IOC是怎么實(shí)現(xiàn)的?
在開始研究源碼之前,樓主有必要介紹一下IOC的一些核心組件,否則一旦進(jìn)入源碼,就會被細(xì)節(jié)捆住,無法從宏觀的角度理解IOC。
BeanFactory:這是IOC容器的接口定義,如果將IOC容器定位為一個水桶,那么BeanFactory 就定義了水桶的基本功能,能裝水,有把手。這是最基本的,他的實(shí)現(xiàn)類可以拓展水桶的功
ApplicationContext:這是我們最常見的,上面我們說水桶,BeanFactory是最基本的水桶,而 ApplicationContext 則是擴(kuò)展后的水桶,它通過繼承MessageSource,ResourceLoader,ApplicationEventPublisher 接口,在BeanFactory 簡單IOC容器的基礎(chǔ)上添加了許多對高級容器的支持。
BeanDefinition:我們知道,每個bean都有自己的信息,各個屬性,類名,類型,是否單例,這些都是bena的信息,spring中如何管理bean的信息呢?對,就是 BeanDefinition, Spring通過定義 BeanDefinition 來管理基于Spring的應(yīng)用中的各種對象以及他們直接的相互依賴關(guān)系。BeanDefinition 抽象了我們對 Bean的定義,是讓容器起作用的主要數(shù)據(jù)類型。對 IOC 容器來說,BeanDefinition 就是對依賴反轉(zhuǎn)模式中管理的對象依賴關(guān)系的數(shù)據(jù)抽象。也是容器實(shí)現(xiàn)依賴反轉(zhuǎn)功能的核心數(shù)據(jù)結(jié)構(gòu)
二、源碼分析
1. 搭建源碼研究環(huán)境
Maven下載即可
2. 開啟研究源碼第一步
public static void main(String[] args) throws ClassNotFoundException {ApplicationContext ctx = new FileSystemXmlApplicationContext ("META-INF/spring/orders-provider.xml");System.out.println("number : " + ctx.getBeanDefinitionCount());RedisUtil ru = (RedisUtil) ctx.getBean("redisUtil");System.out.println(ru); }熟悉的 ApplicatContext ,看名字是應(yīng)用上下文,什么意思呢?就是spirng整個運(yùn)行環(huán)境的背景,好比一場舞臺劇,ApplicatContext 就是舞臺,IOC 管理的Bean 就是演員,Core 就是道具。而ApplicatContext 的標(biāo)準(zhǔn)實(shí)現(xiàn)是 FileSystemXmlApplicationContext。
該類的構(gòu)造方法中包含了容器的啟動,IOC的初始化。所以我們 debug 啟動該項(xiàng)目,運(yùn)行main方法。打好斷點(diǎn)。
3. 從 FileSystemXmlApplicationContext 開始剖析
從這里開始,我們即將進(jìn)入復(fù)雜的源碼。
我們進(jìn)入 FileSystemXmlApplicationContext 的構(gòu)造方法:
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {this(new String[] {configLocation}, true, null); }public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {this(configLocations, true, null); }可以看到該構(gòu)造方法被重載了,可以傳遞 configLocation 數(shù)組,也就是說,可以傳遞過個配置文件的地址。默認(rèn)刷新為true,parent 容器為null。進(jìn)入另一個構(gòu)造器:
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {super(parent);setConfigLocations(configLocations);if (refresh) {refresh();} }該構(gòu)造器做了2件事情,一是設(shè)置配置文件,二是刷新容器,我們可以感覺到,refresh 方法才是初始化容器的重要方法。我們進(jìn)入該方法看看:該方法是 FileSystemXmlApplicationContext 的父類 AbstractApplicationContext 的方法。
4. AbstractApplicationContext.refresh() 方法實(shí)現(xiàn)
/*** 1. 構(gòu)建Be按Factory,以便產(chǎn)生所需要的bean定義實(shí)例* 2. 注冊可能感興趣的事件* 3. 創(chuàng)建bean 實(shí)例對象* 4. 觸發(fā)被監(jiān)聽的事件*/ @Override public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 為刷新準(zhǔn)備應(yīng)用上下文 prepareRefresh();// 告訴子類刷新內(nèi)部bean工廠,即在子類中啟動refreshBeanFactory()的地方----創(chuàng)建bean工廠,根據(jù)配置文件生成bean定義ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 在這個上下文中使用bean工廠 prepareBeanFactory(beanFactory);try {// 設(shè)置BeanFactory的后置處理器 postProcessBeanFactory(beanFactory);// 調(diào)用BeanFactory的后處理器,這些后處理器是在Bean定義中向容器注冊的 invokeBeanFactoryPostProcessors(beanFactory);// 注冊Bean的后處理器,在Bean創(chuàng)建過程中調(diào)用 registerBeanPostProcessors(beanFactory);// 對上下文的消息源進(jìn)行初始化 initMessageSource();// 初始化上下文中的事件機(jī)制 initApplicationEventMulticaster();// 初始化其他的特殊Bean onRefresh();// 檢查監(jiān)聽Bean并且將這些Bean向容器注冊 registerListeners();// 實(shí)例化所有的(non-lazy-init)單件 finishBeanFactoryInitialization(beanFactory);// 發(fā)布容器事件,結(jié)束refresh過程 finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// 為防止bean資源占用,在異常處理中,銷毀已經(jīng)在前面過程中生成的單件bean destroyBeans();// 重置“active”標(biāo)志 cancelRefresh(ex);throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore... resetCommonCaches();}} }可以說該方法就是整個IOC容器初始化的所有邏輯。因此,如果讀懂了該方法的每一行代碼,就了解了spring的整個功能。該方法的調(diào)用層次之深可以想象一下。
我們先大致說下該方法的步驟:
我們一個個來看:
首先構(gòu)建BeanFactory,在哪里實(shí)現(xiàn)的呢?也就是obtainFreshBeanFactory 方法,返回了一個ConfigurableListableBeanFactory,該方法調(diào)用了 refreshBeanFactory() ,該方法是個模板方法,交給了 AbstractRefreshableApplicationContext 去實(shí)現(xiàn)。我們看看該方法實(shí)現(xiàn):
@Override protected final void refreshBeanFactory() throws BeansException {if (hasBeanFactory()) {// 如果存在就銷毀 destroyBeans();closeBeanFactory();}try {// new DefaultListableBeanFactory(getInternalParentBeanFactory())DefaultListableBeanFactory beanFactory = createBeanFactory();// 設(shè)置序列化 beanFactory.setSerializationId(getId());// 定制的BeanFactory customizeBeanFactory(beanFactory);// 使用BeanFactory加載bean定義 AbstractXmlApplicationContext loadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);} }可以看到BeanFactory的創(chuàng)建過程,首先判斷是否存在了 BeanFactory,如果有則銷毀重新創(chuàng)建,調(diào)用 createBeanFactory 方法,該方法中就是像注釋寫的:創(chuàng)建了 DefaultListableBeanFactory ,也既是說,DefaultListableBeanFactory 就是 BeanFactory的默認(rèn)實(shí)現(xiàn)。然后我們看到一個很感興趣的方法,就是 loadBeanDefinitions(beanFactory),看名字是加載 Definitions,這個我們很感興趣,我們之前說過, Definition 是核心之一,代表著 IOC 中的基本數(shù)據(jù)結(jié)構(gòu)。該方法也是個抽象方法,默認(rèn)實(shí)現(xiàn)是 AbstractXmlApplicationContext ,我們看看該方法實(shí)現(xiàn):
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader);loadBeanDefinitions(beanDefinitionReader); }該方法我沒有寫中文注釋,我們看看英文注釋: 首先創(chuàng)建一個 XmlBeanDefinitionReader ,用于讀取XML中配置,設(shè)置了環(huán)境,資源加載器,最后初始化,加載。可以說,該方法將加載,解析Bean的定義,也就是把用戶定義的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化為 IOC容器中的特定數(shù)據(jù)結(jié)構(gòu)。而我們關(guān)心的則是最后一行的 loadBeanDefinitions(beanDefinitionReader) 方法。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {Resource[] configResources = getConfigResources();if (configResources != null) {reader.loadBeanDefinitions(configResources);}String[] configLocations = getConfigLocations();if (configLocations != null) { // 加載給定的路徑文件 reader.loadBeanDefinitions(configLocations);} }該方法會略過第一個if塊,進(jìn)入第二個if塊,進(jìn)入 AbstractBeanDefinitionReader.loadBeanDefinitions(String... locations) 方法,該方法內(nèi)部循環(huán)加載配置文件:
@Override public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {Assert.notNull(locations, "Location array must not be null");int counter = 0;for (String location : locations) {counter += loadBeanDefinitions(location);}return counter; }我們關(guān)心的是 for 循環(huán)中的loadBeanDefinitions(location)方法,該方法核心邏輯在 AbstractBeanDefinitionReader.loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) 方法中:
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {ResourceLoader resourceLoader = getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");}if (resourceLoader instanceof ResourcePatternResolver) {// Resource pattern matching available.try {Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);int loadCount = loadBeanDefinitions(resources); // 根據(jù)配置文件加載bean定義if (actualResources != null) {for (Resource resource : resources) {actualResources.add(resource);}}if (logger.isDebugEnabled()) {logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");}return loadCount;}catch (IOException ex) {throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);}}else {// Can only load single resources by absolute URL.Resource resource = resourceLoader.getResource(location);int loadCount = loadBeanDefinitions(resource);if (actualResources != null) {actualResources.add(resource);}if (logger.isDebugEnabled()) {logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");}return loadCount;} }該方法首先獲取資源加載器,然后進(jìn)入 if 塊,獲取資源數(shù)組,調(diào)用 loadBeanDefinitions(resources) ,根據(jù)配置文件加載Bean定義。進(jìn)入該方法后,循環(huán)加載resource 資源數(shù)組,進(jìn)入 loadBeanDefinitions(resource) 方法中,最后進(jìn)入到 XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) 方法中,該方法主要調(diào)用 doLoadBeanDefinitions(inputSource, encodedResource.getResource()) 方法。我們有必要看看該方法實(shí)現(xiàn):
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {try {Document doc = doLoadDocument(inputSource, resource);return registerBeanDefinitions(doc, resource); // 真正的注冊bean }catch (BeanDefinitionStoreException ex) {throw ex;}catch (SAXParseException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);}catch (SAXException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),"XML document from " + resource + " is invalid", ex);}catch (ParserConfigurationException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"Parser configuration exception parsing XML from " + resource, ex);}catch (IOException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"IOException parsing XML document from " + resource, ex);}catch (Throwable ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"Unexpected exception parsing XML document from " + resource, ex);} }可以看出該方法主要邏輯是根據(jù)輸入流加載 Document 文檔對象,然后根據(jù)得到的文檔對象注冊到容器,因此我們看看倒是是如何注冊到容器的,該方法首先創(chuàng)建一個 BeanDefinitionDocumentReader, 用于讀取 BeanDefinition,該對象會調(diào)用 registerBeanDefinitions(doc, createReaderContext(resource)) 方法,該方法最后從文檔對象總獲取根元素,最后調(diào)用DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(root) 進(jìn)行注冊。該方法最核心的邏輯就是調(diào)用 parseBeanDefinitions(root, this.delegate),我們看看該方法具體實(shí)現(xiàn):
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {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;if (delegate.isDefaultNamespace(ele)) {parseDefaultElement(ele, delegate); // 解析 }else {delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);} }該方法就是一個解析XML 文檔的步驟,核心是調(diào)用 parseDefaultElement(ele, delegate),我們進(jìn)入該方法查看,該方法調(diào)用了 processBeanDefinition(ele, delegate) 方法進(jìn)行解析。我們有必要看看該方法:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); // 解析if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// Register the final decorated instance.BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); // 開始注冊 }catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name '" +bdHolder.getBeanName() + "'", ele, ex);}// Send registration event.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));} }首先創(chuàng)建一個 BeanDefinitionHolder,該方法會調(diào)用 BeanDefinitionReaderUtils.registerBeanDefinition 方法, 最后執(zhí)行容器通知事件。該靜態(tài)方法實(shí)現(xiàn)如下:
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {// Register bean definition under primary name.String beanName = definitionHolder.getBeanName();registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// Register aliases for bean name, if any.String[] aliases = definitionHolder.getAliases();if (aliases != null) {for (String alias : aliases) {registry.registerAlias(beanName, alias);}} }可以看到首先從bean的持有者那里獲取了beanName,然后調(diào)用 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()), 將bena的名字和 BeanDefinition 注冊,我們看看最后的邏輯:
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {Assert.hasText(beanName, "Bean name must not be empty");Assert.notNull(beanDefinition, "BeanDefinition must not be null");if (beanDefinition instanceof AbstractBeanDefinition) {try {((AbstractBeanDefinition) beanDefinition).validate();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,"Validation of bean definition failed", ex);}}BeanDefinition oldBeanDefinition;oldBeanDefinition = this.beanDefinitionMap.get(beanName);if (oldBeanDefinition != null) {if (!isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +"': There is already [" + oldBeanDefinition + "] bound.");}else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTUREif (this.logger.isWarnEnabled()) {this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +"' with a framework-generated bean definition: replacing [" +oldBeanDefinition + "] with [" + beanDefinition + "]");}}else if (!beanDefinition.equals(oldBeanDefinition)) {if (this.logger.isInfoEnabled()) {this.logger.info("Overriding bean definition for bean '" + beanName +"' with a different definition: replacing [" + oldBeanDefinition +"] with [" + beanDefinition + "]");}}else {if (this.logger.isDebugEnabled()) {this.logger.debug("Overriding bean definition for bean '" + beanName +"' with an equivalent definition: replacing [" + oldBeanDefinition +"] with [" + beanDefinition + "]");}}this.beanDefinitionMap.put(beanName, beanDefinition);}else {if (hasBeanCreationStarted()) {// Cannot modify startup-time collection elements anymore (for stable iteration)synchronized (this.beanDefinitionMap) {this.beanDefinitionMap.put(beanName, beanDefinition);List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;if (this.manualSingletonNames.contains(beanName)) {Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);updatedSingletons.remove(beanName);this.manualSingletonNames = updatedSingletons;}}}else {// Still in startup registration phase // 最終放進(jìn)這個map 實(shí)現(xiàn)注冊this.beanDefinitionMap.put(beanName, beanDefinition);// 走這里this.beanDefinitionNames.add(beanName);this.manualSingletonNames.remove(beanName);}this.frozenBeanDefinitionNames = null;}if (oldBeanDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);} }該方法可以說是注冊bean的最后一步,將beanName和 beanDefinition 放進(jìn)一個 ConcurrentHashMap(256) 中。
那么這個 beanDefinition 是時候創(chuàng)建的呢? 就是在 DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法中,在這里創(chuàng)建了 BeanDefinitionHolder, 而該實(shí)例中解析Bean并將Bean 保存在該對象中。所以稱為持有者。該實(shí)例會調(diào)用 parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) 方法,該方法用于解析XML文件并創(chuàng)建一個 BeanDefinitionHolder 返回,該方法會調(diào)用 parseBeanDefinitionElement(ele, beanName, containingBean) 方法, 我們看看該方法:
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {this.parseState.push(new BeanEntry(beanName));String className = null;if (ele.hasAttribute(CLASS_ATTRIBUTE)) {className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); // 類全限定名稱 }try {String parent = null;if (ele.hasAttribute(PARENT_ATTRIBUTE)) {parent = ele.getAttribute(PARENT_ATTRIBUTE);}AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 創(chuàng)建 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));parseMetaElements(ele, bd);parseLookupOverrideSubElements(ele, bd.getMethodOverrides());parseReplacedMethodSubElements(ele, bd.getMethodOverrides());parseConstructorArgElements(ele, bd);parsePropertyElements(ele, bd);parseQualifierElements(ele, bd);bd.setResource(this.readerContext.getResource());bd.setSource(extractSource(ele));return bd;}catch (ClassNotFoundException ex) {error("Bean class [" + className + "] not found", ele, ex);}catch (NoClassDefFoundError err) {error("Class that bean class [" + className + "] depends on not found", ele, err);}catch (Throwable ex) {error("Unexpected failure during bean definition parsing", ele, ex);}finally {this.parseState.pop();}return null; }我們看看該方法,可以看到,該方法從XML元素中取出 class 元素,然后拿著className調(diào)用 createBeanDefinition(className, parent) 方法,該方法核心是調(diào)用 BeanDefinitionReaderUtils.createBeanDefinition 方法,我們看看該方法:
public static AbstractBeanDefinition createBeanDefinition(String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {GenericBeanDefinition bd = new GenericBeanDefinition(); // 泛型的bean定義,也就是最終生成的bean定義。 bd.setParentName(parentName);if (className != null) {if (classLoader != null) {bd.setBeanClass(ClassUtils.forName(className, classLoader)); // 設(shè)置Class }else {bd.setBeanClassName(className);}}return bd; }該方法很簡單,創(chuàng)建一個 Definition 的持有者,然后設(shè)置該持有者的Class對象,該對象就是我們在配置文件中配置的Class對象。最后返回。
到這里,我們一走完了第一步,創(chuàng)建bean工廠,生成Bean定義。但還沒有實(shí)例化該類。
5. 如何創(chuàng)建Bean實(shí)例并構(gòu)建Bean的依賴關(guān)系網(wǎng)
我們剛剛創(chuàng)建了Bean工廠,并創(chuàng)建 BeanDefinitions 放進(jìn)Map里,以beanName為key。那么我們現(xiàn)在有了Bean定義,但還沒有實(shí)例,也沒有構(gòu)建Bean與Bean之間的依賴關(guān)系。我們知道,構(gòu)建依賴關(guān)系是 IOC 的一個重要的任務(wù),我們怎么能放過。那么是在哪里做的呢?在 finishBeanFactoryInitialization(beanFactory) 方法中。該方法中重要的一步是 : beanFactory.preInstantiateSingletons(),我們有必要看看該方法實(shí)現(xiàn):
public void preInstantiateSingletons() throws BeansException {if (this.logger.isDebugEnabled()) {this.logger.debug("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); // 注意:FactoryBeanboolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {@Overridepublic Boolean run() {return ((SmartFactoryBean<?>) factory).isEagerInit();}}, getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}else {getBean(beanName); // 創(chuàng)建bean }}}// Trigger post-initialization callback for all applicable beans...for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {smartSingleton.afterSingletonsInstantiated();return null;}}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}} }該方法首先循環(huán)所有的BeanNames,并且調(diào)用getBean方法,該方法實(shí)際上就是創(chuàng)建bean并遞歸構(gòu)建依賴關(guān)系。該方法會調(diào)用 doGetBean(name, null, null, false),我們進(jìn)入該方法查看,該方法很長,樓主挑選重要代碼:
String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}registerDependentBean(dep, beanName);getBean(dep); // 遞歸 } }// Create bean instance. if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {@Overridepublic Object getObject() throws BeansException {try {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); }可以看到,該方法首先會獲取依賴關(guān)系,拿著依賴的BeanName 遞歸調(diào)用 getBean方法,直到調(diào)用 getSingleton 方法返回依賴bean,而 getSingleton 方法的參數(shù)是 createBean 返回的實(shí)例,該方法內(nèi)部調(diào)用 AbstractAutowireCapableBeanFactory.doCreateBean 方法:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);mbd.resolvedTargetType = beanType;// Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isDebugEnabled()) {logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}addSingletonFactory(beanName, new ObjectFactory<Object>() {@Overridepublic Object getObject() throws BeansException {return getEarlyBeanReference(beanName, mbd, bean);}});}// Initialize the bean instance.Object exposedObject = bean;try {populateBean(beanName, mbd, instanceWrapper);if (exposedObject != null) {exposedObject = initializeBean(beanName, exposedObject, mbd);}}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject; }該方法很長,我們只關(guān)注二行代碼:
我們看看 createBeanInstance 方法:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {// Make sure bean class is actually resolved at this point.Class<?> beanClass = resolveBeanClass(mbd, beanName);if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());}if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}// Shortcut when re-creating the same bean...boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}if (resolved) {if (autowireNecessary) {return autowireConstructor(beanName, mbd, null, null);}else {return instantiateBean(beanName, mbd);}}// Need to determine the constructor...Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors != null ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);}// No special handling: simply use no-arg constructor.return instantiateBean(beanName, mbd); }該方法的doc注釋是這樣介紹的:為指定的bean創(chuàng)建一個新的實(shí)例,使用適當(dāng)?shù)膶?shí)例化策略:工廠方法、構(gòu)造函數(shù)自動裝配或簡單實(shí)例化。我們看,該方法首先創(chuàng)建Class 對象,然后獲取構(gòu)造器對象,最后調(diào)用 instantiateBean(beanName, mbd) 方法,我們看看該方法實(shí)現(xiàn):
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {try {Object beanInstance;final BeanFactory parent = this;if (System.getSecurityManager() != null) {beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {return getInstantiationStrategy().instantiate(mbd, beanName, parent);}}, getAccessControlContext());}else {beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);}BeanWrapper bw = new BeanWrapperImpl(beanInstance);initBeanWrapper(bw);return bw;}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);} }該方法核心邏輯是 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent),攜帶BeanName ,RootBeanDefinition ,發(fā)揮的策略對象是 SimpleInstantiationStrategy,該方法內(nèi)部調(diào)用靜態(tài)方法 BeanUtils.instantiateClass(constructorToUse), 組后調(diào)用 Constructor 的 newInstance 方法, 也就是最終使用反射創(chuàng)建了該實(shí)例:
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {Assert.notNull(ctor, "Constructor must not be null");try {ReflectionUtils.makeAccessible(ctor);return ctor.newInstance(args);}catch (InstantiationException ex) {throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);}catch (IllegalAccessException ex) {throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);}catch (IllegalArgumentException ex) {throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);}catch (InvocationTargetException ex) {throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());} }該方法會判斷是否是 Kotlin 類型。如果不是,則調(diào)用構(gòu)造器的實(shí)例方法。
到這里,我們的實(shí)例已經(jīng)創(chuàng)建。但是我們的實(shí)例的依賴還沒有設(shè)置,剛剛我們在 doCreateBean 方法說關(guān)心2行代碼:
我們已經(jīng)解析了第一個,現(xiàn)在看第二個方法:
我們看看該方法:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {PropertyValues pvs = mbd.getPropertyValues();if (bw == null) {if (!pvs.isEmpty()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");}else {// Skip property population phase for null instance.return;}}// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the// state of the bean before properties are set. This can be used, for example,// to support styles of field injection.boolean continueWithPropertyPopulation = true;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {continueWithPropertyPopulation = false;break;}}}}if (!continueWithPropertyPopulation) {return;}if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}pvs = newPvs;}boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);if (hasInstAwareBpps || needsDepCheck) {PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);if (hasInstAwareBpps) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvs == null) {return;}}}}if (needsDepCheck) {checkDependencies(beanName, mbd, filteredPds, pvs);}}applyPropertyValues(beanName, mbd, bw, pvs); }該方法核心邏輯是 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null), 即獲取該bean的所有屬性,也就是我們配置property元素。最后執(zhí)行 applyPropertyValues(beanName, mbd, bw, pvs) 方法。注意,現(xiàn)在的PropertyValues 都是字符串,沒有值的,這個方法的作用就是獲取值,關(guān)鍵代碼:Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue),該方法會獲取 pvName 所對應(yīng)的容器value,該方法內(nèi)部會調(diào)用 BeanWrapperImpl.resolveReference(argName, ref) 方法,我們看看該方法:
private Object resolveReference(Object argName, RuntimeBeanReference ref) {try {String refName = ref.getBeanName();refName = String.valueOf(doEvaluate(refName));if (ref.isToParent()) {if (this.beanFactory.getParentBeanFactory() == null) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName,"Can't resolve reference to bean '" + refName +"' in parent factory: no parent factory available");}return this.beanFactory.getParentBeanFactory().getBean(refName);}else {Object bean = this.beanFactory.getBean(refName);this.beanFactory.registerDependentBean(refName, this.beanName);return bean;}}catch (BeansException ex) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName,"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);} }其中有一行熟悉的代碼:bean = this.beanFactory.getBean(refName),對,這里就是發(fā)生遞歸的地方。該方法會拿著屬性名稱從容器中獲取實(shí)例。
我們回到 applyPropertyValues 方法。此時deepCopy 集合已經(jīng)有值了,不再僅僅是字符串了。然后調(diào)用 setPropertyValues(new MutablePropertyValues(deepCopy)) 方法, 該方法會調(diào)用 AbstractPropertyAccessor.setPropertyValues 方法完成注入,而該方法會循環(huán)元素列表, 循環(huán)中調(diào)用 setPropertyValue(PropertyValue pv) 方法, 該方法最后會調(diào)用 nestedPa.setPropertyValue(tokens, pv) 方法, 該方法又會調(diào)用 processLocalProperty(tokens, pv) 方法,該方法最后又會調(diào)用 ph.setValue(valueToApply) 方法,也就是BeanWrapperImpl.setValue() 方法,終于,我們要看到反射了,看到反射說明到了盡頭。
@Override public void setValue(final Object object, Object valueToApply) throws Exception {final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :this.pd.getWriteMethod());if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {if (System.getSecurityManager() != null) {AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {writeMethod.setAccessible(true);return null;}});}else {writeMethod.setAccessible(true);}}final Object value = valueToApply;if (System.getSecurityManager() != null) {try {AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {@Overridepublic Object run() throws Exception {writeMethod.invoke(object, value);return null;}}, acc);}catch (PrivilegedActionException ex) {throw ex.getException();}}else {writeMethod.invoke(getWrappedInstance(), value);} }該方法是最后一步,我們看到該方法會找的set方法,然后調(diào)用 Method 的 invoke 方法,完成屬性注入。
真的不容易。
三、總結(jié)
我們從源碼層面剖析 IOC 的初始化過程,也了解了 IOC 的底層原理實(shí)現(xiàn), 我們總結(jié)一下: Spring 的 Bean 其實(shí)就是 BeanDefinition, 在 Bean 的創(chuàng)建和依賴注入的過程中, 需要根據(jù) BeanDefinition 的信息來遞歸的完成依賴注入, 從我們分析的代碼可以看到,這些遞歸都是以 getBean() 為入口的, 一個遞歸是在上下文體系中查找需要的 Bean 和創(chuàng)建 Bean 的遞歸調(diào)用, 另一個 Bean 實(shí)在依賴注入時,通過遞歸調(diào)用容器的 getBean 方法, 得到當(dāng)前的依賴 Bean, 同時也觸發(fā)對依賴 Bean 的創(chuàng)建和注入. 在對 Bean 的屬性盡心依賴注入時, 解析的過程也是一個遞歸的過程, 這樣, 根據(jù)依賴關(guān)系, 一層一層的完成 Bean 的創(chuàng)建和注入, 知道最后完成當(dāng)前 Bean 的創(chuàng)建, 有了這個頂層 Bean 的創(chuàng)建和對他的屬性依賴注入的完成, 意味著當(dāng)前 Bean 相關(guān)的整個依賴鏈的注入也完成了.
總結(jié)一下 IOC 的初始化過程吧:
轉(zhuǎn)載于:https://www.cnblogs.com/yifanSJ/p/9232382.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的深入理解 Spring 之源码剖析IOC的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。