? ? ? ? 我們知道,在Spring中,一個Bean可以理解為一個對象,但是二者之間肯定是有區別的,比如一個Bean可以實例化成很多個對象、Bean中可以帶有某些描述信息。
? ? ? ? 學習Bean,能更好地使用Bean。
1、Spring兩個核心概念的由來【可忽略】
? ? ? ? Spring最關鍵的功能就是實現IOC依賴翻轉,其依賴翻轉的實現靠的是設計模式“工廠模式”,所以,Spring中有一個核心概念,叫做工廠“Factory”。【當然,我們一般使用BeanFactory接口】
? ? ? ? 只有工廠,那么每次客戶端(如果我們把Spring的客戶---即程序員,看成客戶端)調用某個對象,就可能要重新new一個對象(或者靠反射實例化一個對象)。
? ? ? ? new對象沒有關系,最核心的是我們是在XML文件(或者Java配置類,又或者注解開發)里配置bean屬性的,如果每次new對象,都要解析XML文件,那么性能會很低。
? ? ? ? 那么,為什么不用一個倉庫,把所有的對象實例化后,存儲起來呢?
????????【保持疑問:懶加載lazy--load屬性,能支持每次使用bean時,才創建,好像和new對象沒區別?(目標:找出它們的區別)】
? ? ? ? 既然想要一個倉庫,就得有一個統一的“商品”,否則,我們沒法用一種統一的方法,存儲某個對象(比如自定義的3個類Student、Teacher、Course,3個類是有區別的)
? ? ? ? 由于Java里,所有的類都指向Object,所以用Object當“商品”是個好主意。
? ? ? ? 不過,Object想強轉為某個類型(比如student),也得事先知道這是student。
? ? ? ? 在Spring的早期版本,程序員使用BeanFactory創建Bean時,調用getBean方法,都要強轉,這沒什么問題。
? ? ? ? 然而,隨著Spring的發展,我們逐漸摒棄這種做法,更多采用@Autowired注解自動實例化,這時候,強轉就是一個問題了。
? ? ? ? 先分析這個問題。第一,強轉的關鍵在于,我們事先不知道這個bean,是不是Student類,所以需要交給程序員手動處理。第二,@Autowired注解的關鍵是,我們要找到@Autowired對象和某個類的聯系。【比如你在Student類中,用@Autowired注解了下面的語句“private Teacher tea”,那么要找到Student和Teacher的關系】(當然,這通過反射好像也能解決,不過也許性能問題吧。)
? ? ? ? 所以,我們需要一個類,至少有2個屬性。第一,標注這個bean指向哪個類;第二,標注這個bean,可能需要哪個類(當然,現在要求指向另一個bean,不過也說得通,如果Spring能夠直接拿到另一個非bean的對象,那么其侵入性就太強了)
? ? ? ? 當然,這不是BeanDefinition誕生的原因,我們也能發現,早期Spring版本是需要手動強轉的。
? ? ? ? 不過,舉了這個例子,我們能發現,如果用Object類作為“商品”,其拓展性就很低。
? ? ? ? 如果用某個類X,繼承Object呢?可行,不過問題在于,X會繼承Object的所有屬性和方法,某種情況下我們不希望這么做。(比如性能損耗、或者希望內外部溝通的方法唯一)
? ? ? ? 所以,干脆一不做二不休,采用一個接口BeanDefinition,作為“商品”。
? ? ? ? 可能你會問了:Object是所有類和接口的基類,所有類和接口,都直接或間接指向Object,那定義這個接口,不也是一樣?
? ? ? ? 其實,Java這樣定義是為了統一的類結構,在實際使用時,會發現接口無法調用Object的方法,所以其實并沒有繼承。【這也符合Java中,接口不能繼承自具體類的原則】
? ? ? ? (當然了,為了保持拓展性,Spring還定義了一個接口AttributeAccessor,使接口BeanDefinition繼承AttributeAccessor)【Spring很多其它概念,都繼承了這個接口】
? ? ? ? 此時,問題解決了一些,另一個在Java語法層面的問題是:
? ? ? ? 接口不能定義變量,任何屬性在接口里,都必須是public、static和final的。
? ? ? ? 所以,我們需要在BeanDefinition接口的某個實現類中,定義這些屬性。
? ? ? ? 實現了BeanDefinition接口的抽象類AbstractBeanDefinition中,就定義了這些屬性。
? ? ? ? 其它實現BeanDefinition接口的類,直接或間接都繼承了AbstractBeanDefinition類。【可以說這是最重要的類之一】
2、Spring中,BeanDefinition定義的信息
? ? ? ? 其實在應用層面,我們很少使用BeanDefinition,一般都是配置后@Autowired。
? ? ? ? 當然,了解BeanDefinition的一些屬性,對開發也大有幫助。
第一,BeanDefinition的類特征信息定義
? ? ? ? 類信息定義,主要功能是,外部拿bean和內部找到類。
? ? ? ? 1.類名:bean的唯一名稱,依靠此名稱,從工廠Factory找到bean【getBean方法的字符串就是它的名字】
? ? ? ? 2.指向的類:bean對應的類,一般是從工程目錄java往下的相對路徑。
第二,BeanDefinition的內部屬性信息定義
? ? ? ? 主要功能是,實現內部的一些功能。
? ? ? ? 1.Scope作用域(我個人覺得應該叫類型):原生Spring有2種,單例singleton和原型prototype。(在其它情況可能會多出幾種)【這定義了,當外部使用bean時,我們Spring是每次重新new一個bean(原型),還是永遠返回同一個bean(單例)】
? ? ? ? 2.primary主要的:
????????????????假設有1接口叫FX,他有n個實現類。
????????????????其中,類X的配置中,設置了這個屬性。
????????????????那么,如果Spring內部某個類AAA有成員變量FX,使用@Autowired時,默認實例化類X。
? ? ? ? 3.依賴信息:比如該bean需要依賴哪些類。
? ? ? ? 4.懶加載lazy-load:如果定義了這個,Spring不會一開始就實例化bean。
第三,行為信息定義
? ? ? ? 主要功能是,定義外部使用bean時,可以做的操作。
? ? ? ? 1.初始化方法:在bean實例化后,會調用該方法。
? ? ? ? 2.銷毀方法:在bean銷毀前,會調用該方法。
此外,BeanDefinition還有一些其它屬性,所以我用得不多,在此不說明。
?????????我是蚊子碼農,如有補充或者疑問,歡迎在評論區留言。個人的知識體系可能沒有那么完善,希望各位多多指正,謝謝大家。