前言程序員
使用 Java 做爲第一開發語言的朋友們,相信你們或多或少的都使用過 Spring 這個開發框架,能夠說 Spring 框架真是咱們 Java 程序員的春天,在 Spring 中 Bean 是其中最重要的概念之一,是學習其它高級知識的基礎,Bean 說白了其實就是一個被 Spring 框架管理的對象,今天咱們來看看 Bean 在 Spring 中是如何被造出來的。框架
Bean 要如何定義ide
假如你有以下這樣的一個 Programmer 類,這個程序員類有三個屬性:姓名(name)、年齡(age)、是否有女友(hasGirlFriend)(P.S. 正常狀況下 hasGirlFriend 屬性應該都是 false),還有一個顯示我的資料的方法 showMaterial。函數
/** * @Author: mghio * @Date: 2020-10-05 * @Description: Programmer. */ public class Programmer { private String name; private Integer age; private Boolean hasGirlFriend; public void showMaterial() { System.out.println("name: " + name + ", age: " + age + ", hasGirlFriend: " + hasGirlFriend); } }
如今請你思考一下,若是讓你來設計該如何在一個 Spring 容器中描述這樣的一個 Programmer 對象呢?學習
無非就是須要以下這些信息:ui
2.1設計
類名code
首先類名確定是須要的,這樣到時候才能經過類名加載到這個類。對象
2.2blog
實例別名
當咱們在一個容器中若是一個類有多個實例或者不想經過一個類名來描述一個實例時,這時經過設置一個別名就能夠很方便的描述該實例了。
2.3
構造函數
咱們知道 Java 中建立一個類的實例首先就會調用該類的構造函數,當有多個構造函數時,須要明確的描述要使用哪一個構造函數來建立對象,好比經過傳入不一樣的參數類型來選擇不一樣的構造函數。
2.4
類的屬性設置
當咱們沒有在構造函數中傳入屬性,好比上面的 Programmer 能夠直接經過無參構造函數就能夠建立出來了,後面若是須要設置實例的屬性則須要調用其設置屬性的方式來進行設置,因此屬性方法也是必要的。
2.5
初始化方法
有時候咱們須要在一個實例化完成以後作一些咱們自定義的業務邏輯,好比想讓上面例子中的 Programmer 在實例化完成以後就顯示我的資料(調用 showMaterial() 方法),這種場景使用初始化方法就很合適了。
2.6
銷燬方法
說到銷燬,你們可能都會想到和資源有關,好比一個共識就是你們通常都把資源釋放類的工做放在 finally 代碼塊中確保資源能夠獲得釋放,一樣當一個 Bean 以後鏈接使用了某些資源時,當銷燬後想要對這些資源進行釋放,這時候就能夠經過其 銷燬方法 來釋放資源。
2.7
做用域
有些 Bean 可能須要在整個容器中只有一個,也就是單例,而有些可能要求每一次請求對應的 Bean 都不同,這時能夠經過一個 做用域 的概念,來區分不一樣要求的 Bean,當容器發現這個類是 單例 的,就會複用已存在的 Bean,不然才從新建立。
固然這裏只是列舉一些我的以爲比較重要的屬性,還有其它的一些屬性須要增長。在 Spring 框架中 Bean 的定義是經過一個 BeanDefinition 類來描述的。
在沒有使用 SpringBoot 以前咱們都是經過 XML 配置而後 Spring 來解析生成 Bean 的,同時咱們也能夠經過代碼方式使用 BeanDefinitionBuilder 生成 Bean,具體代碼以下所示:
/** * @Author: mghio * @Date: 2020-10-05 * @Description: */ public class ProgrammerTest { public static void main(String[] args) { new Programmer().showMaterial(); BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Programmer.class); beanDefinitionBuilder.addPropertyValue("name", "mghio"); beanDefinitionBuilder.addPropertyValue("age", 18); beanDefinitionBuilder.addPropertyValue("hasGirlFriend", false); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerBeanDefinition("programmer", beanDefinitionBuilder.getBeanDefinition()); Programmer programmer = (Programmer) beanFactory.getBean("programmer"); programmer.showMaterial(); } }
運行結果以下:
在使用 XML 方式時通常是經過調用 ClassPathXmlApplicationContext 來註冊 Bean 的,其構造函數能夠傳入具體的 XMl 配置文件的路徑,能夠是一個或者多個,甚至還能夠是通配符。在構造函數內部就會調用熟悉的 refresh 方法了。
深刻 refresh 方法能夠發現,在該方法中調用了 obtainFreshBeanFactory 方法來獲取生成的 Bean,這個方法其實是調用了抽象實現類 AbstractRefreshableApplicationContext 的 refreshBeanFactory 方法,該方法首先會先判斷此時是否還有 beanFactory ,若是有的話會先銷燬 beanFactory,而後再從新建立一個 BeanFactory(其實是 DefaultListableBeanFactory 類型),最後會調用 loadBeanDefinitions 加載咱們定義的 XMl 配置,方法使用的是 XmlBeanDefinitionReader 來讀取的 XMl 配置,下面一塊兒來深刻的瞭解一下 Spring 生成 Bean 的過程。
建立 Bean 的過程
首先咱們看看 BeanFactory 類圖,以下所示:
Bean 的總體建立流程以下所示:
總結
本文簡要的講述了 Spring 建立 Bean 的主要流程,還有許多細節的地方須要深刻研讀源碼才能瞭解,在這裏先給本身一個小目標,後續會本身實現一個簡易版本的 Spring(IOC、AOP),預知後事如何,請聽下回分解。。。