1. 程式人生 > >品Spring:帝國的基石

品Spring:帝國的基石




生活是一杯酒,有時需要麻醉自己,才能夠暫時忘卻痛苦與不快。
生活是一杯茶,有時需要細細品味,才發現苦澀背後也會有甘甜。

Spring是一杯酒,一眼望不到邊的官方文件,著實讓人難以下嚥。
Spring是一杯茶,在無邊的原始碼中暢遊之後,發現色相味道俱全。

高考狀元是六月份的網紅,Spring帝國是Java界的明星。
狀元有自己的“武功祕籍”,Spring有自己的“帝國基石”。

請隨本文一起,品Spring,尋找帝國的基石。


帝國的基石


無論是大到一個國家,或是小到一個個人,都有自己賴以存在的基石。這個基石就是核心支柱,就像經濟基礎支撐著上層建築。

以BAT來說,百度的搜尋,阿里的電商,騰訊的社交。可以說這是他們的立司之本,如果想在這些方面和他們PK,幾乎沒有勝算的可能。


Spring絕對是Java開發領域中一顆閃耀的明星,它的巨大光芒甚至一直在引領著Java的發展方向。

現在說它已經發展為一個帝國,應該不會有人站出來反對吧。嗯,站出來也沒關係,本人不接受反對。哈哈。

那麼有一個問題,請大家思考下,Spring帝國的基石是什麼?

用過或瞭解Spring的人肯定都會說是IoC啦,AOP啦,宣告式事務啦等等。只能說這些回答浮於表面,明顯不走心啊。

好了,我來公佈答案吧,這個帝國的基石,其實就是Bean。肯定會有人問,這個bean是什麼東西啊,那就去看它的定義吧。對,就是Spring中的bean定義。

在Spring中,bean定義其實就是一個介面,即BeanDefinition。我在上一篇“畢業十年”的文章中說過,我們定義的類或介面其實都是對一種資料構成的描述,所以可以直接把類或介面看作是一種資料結構。

那麼bean定義介面,就是一種資料結構,它記錄了一個bean的全部資訊,後期Spring對這個bean的所有操作都是建立在這些資訊之上的。

如果對Spring不是很熟悉的朋友,聽到“bean的全部資訊”這句話會有點懵。不要擔心,照例拿生活中我們熟悉的事物去做類比,爭取讓所有人都能明白。

在醫療行業,每個患者都會有一個病歷,上面記錄了患者家族病史,患者個人病史,都做過哪些檢查以及檢查結果,都做過哪些治療以及恢復情況。還有大夫每次對患者的病情診斷與分析。

這些資訊肯定是記錄的越全面越好,後續的治療方案都是依賴這些資訊而制定的。Spring中bean的資訊就對等於這裡患者的病歷資訊。

在公安系統,每個嫌疑人也會有一個檔案,上面記錄了他的口供,作案資訊或一些其它證據,同樣這些資訊蒐集的越全面越好,後期法官的宣判與量刑也都依賴於它。

那麼在這裡,記錄案件資訊的檔案,就可以對等於Spring中bean的資訊。

相信通過這兩個示例,你已經完全明白了這個bean資訊的作用和地位。雖然到目前為止,你可能還真不知道它裡面到底儲存的是什麼資訊。但這不要緊,只要記住它非常重要就可以了。

趁著這個機會,再小小拓展一下:

這裡的病歷資訊和檔案資訊裡面記錄的都是一些資料,所以可以認為它們對應於程式中的資料結構。

醫生的治療方案和法官的宣判,其實都是依賴這些資料做出的決定,因此可以認為它們對應於程式中的演算法。

可見,資料結構決定著演算法,或者說,演算法是基於資料結構而設計的。

因此,可以說資料結構的重要性要大於演算法。良好的資料結構能簡化演算法,不好的資料結構只能使演算法變得更復雜。


跟著變化走,把它當朋友


在上篇文章中提到過,唯一不變的就是變化,所以隨著時間的推移,只需不斷往這個資料結構中補充新的bean資訊,Spring再利用這些補充資訊去定義新的操作,以適應發展的需要。

就是這樣,Spring一步一步成長為一個浩浩蕩蕩的帝國。就像我在上一遍文章中說的,類或介面這樣的資料結構一定要進行精心設計,這樣程式碼寫起來會簡單些,而且後期改起來也會容易些。

一個非常明顯的例子,一開始都是基於XML配置檔案的,現在都是基於註解或Java配置的,可以說Spring完成了一次華麗的轉身,而且非常完美絲滑,沒有一點拖泥帶水。

其實就是在bean定義資料結構中加入了註解和Java配置相關的資訊,Spring利用這些資訊去重新實現一遍,並且和基於XML的實現並存,因此既可以用XML也可以用註解。

就像我在上一篇文章中說的,一定要合理抽象,從巨集觀整體把握,良好定義整體架構或結構,至於一些具體的區域性實現細節,可以根據實際情況來定。

因為區域性實現涉及範圍一般較小,後期換用新的方式來個重新實現也會相對容易一些。從XML到註解基本就是這樣子的。

其實說實話,上一篇文章就是從這一篇分離出去的,專門為本篇文章埋伏筆、做鋪墊用的。哈哈。

滔滔不絕的說了這麼多,快來看看廬山真面目吧。


最討厭的就是原始碼


有句話是怎麼說的呢,“要不是為了生活,誰願意把自己弄得滿身才華”。哈哈,看原始碼時多想想這句話。

不想看的,直接跳過吧。

BeanDefinition介面,及bean定義,下面只列出了get方法,其實還有set方法:

bean定義可以繼承
String getParentName();

bean對應的類名稱,用來例項化bean
String getBeanClassName();

生命週期範圍
String getScope();

是否延遲例項化
boolean isLazyInit();

依賴的其它bean
String[] getDependsOn();

是否作為自動裝配候選bean
boolean isAutowireCandidate();

是否是主要的,用在可能有多個候選bean的情況
boolean isPrimary();

一個用來生成該bean的工廠bean名稱
String getFactoryBeanName();

一個用來生產該bean的工廠方法名稱
String getFactoryMethodName();

bean的建構函式
ConstructorArgumentValues getConstructorArgumentValues();

一些key/value,可以在bean例項化後設置給bean的屬性
MutablePropertyValues getPropertyValues();

初始化方法名稱
String getInitMethodName();

銷燬方法名稱
String getDestroyMethodName();

角色,應用層/基礎設施層
int getRole();

人類可讀的描述
String getDescription();

是否單例
boolean isSingleton();

是否原型
boolean isPrototype();

是否抽象
boolean isAbstract();


這兩點比較關鍵,需要知道:

可以有兩種方法來指定一個bean的定義,一個是類名稱,一個是工廠方法。

單例和原型這兩種生命週期不是互斥關係,因為存在既不是單例也不是原型的,如request、session等範圍。


AnnotatedBeanDefinition介面,擴充套件了bean定義介面,增加了註解相關資訊:

AnnotationMetadata getMetadata();

MethodMetadata getFactoryMethodMetadata();


ClassMetadata介面,是通過類註冊時,和類相關的一些資訊:

String getClassName();

boolean isInterface();

boolean isAnnotation();

boolean isAbstract();

boolean isConcrete();

boolean isFinal();

boolean isIndependent();

boolean hasEnclosingClass();

String getEnclosingClassName();

boolean hasSuperClass();

String getSuperClassName();

String[] getInterfaceNames();

String[] getMemberClassNames();



MethodMetadata介面,是通過工廠方法註冊時,和方法相關的資訊:

String getMethodName();

String getDeclaringClassName();

String getReturnTypeName();

boolean isAbstract();

boolean isStatic();

boolean isFinal();

boolean isOverridable();



AnnotatedTypeMetadata介面,用於獲取註解的屬性資訊:

boolean isAnnotated(String annotationName);

Map<String, Object> getAnnotationAttributes(String annotationName);

Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString);

MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName);

MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString);



AnnotationMetadata介面,用於獲取一個類上標有的註解資訊:

Set<String> getAnnotationTypes();

Set<String> getMetaAnnotationTypes(String annotationName);

boolean hasAnnotation(String annotationName);

boolean hasMetaAnnotation(String metaAnnotationName);

boolean hasAnnotatedMethods(String annotationName);

Set<MethodMetadata> getAnnotatedMethods(String annotationName);




一個小示例


上面的東西太抽象了,下面通過一個簡單的示例,來具體看下。

使用@Component註解註冊一個Boss類的bean定義。

@Component
public class Boss {

}



使用@Configuration類裡的@Bean方法註冊兩個Staff的bean定義,同時Company類的bean定義也會被註冊。

public class Staff {

}

@Configuration
public class Company {

    @Bean
    public Staff littleMing() {
        return new Staff();
    }

    @Bean
    public Staff littleQiang() {
        return new Staff();
    }
}



在註冊bean定義時,需要一個bean名稱,預設會自動生成,就是首字母小寫的類名或方法名。

因此,以上四個bean定義的名稱分別是:

boss
company
littleMing
littleQiang



既然已經到這裡了,就應該滿足一下好奇心,取出bean定義看看,是什麼樣子。

下面是Boss類的bean定義:

            
           

相關推薦

Spring帝國基石

序生活是一杯酒,有時需要麻醉自己,才能夠暫時忘卻痛苦與不快。生活是一杯茶,有時需要細細品味,才發現苦澀背後也會有甘甜。Spring是一杯酒,一眼望不到邊的官方文件,著實讓人難以下嚥。Spring是一杯茶,在無邊的原始碼中暢遊之後,發現色相味道俱全。高考狀元是六月份的網紅,Spring帝國是Java界的明星。狀

Springbean定義上梁山

認真閱讀,收穫滿滿,向智慧又邁進一步。。。技術不枯燥,先來點閒聊先說點好事高興一下。前段時間看新聞說,我國正式的空間站建設已在進行當中。下半年,長征五號B運載火箭將在海南文昌航天發射場擇機將空間站核心艙發射升空。預計用2到3年將空間站建好。雖然到時你們不讓我上去,不過我也為這件事出不了什麼力,算扯平了。哈哈,

Spring實現bean定義時採用的“先進生產力”

前景回顧當我們把寫好的業務程式碼交給Spring之後,Spring都會做些什麼呢?仔細想象一下,再稍微抽象一下,Spring所做的幾乎全部都是:“bean的例項化,bean的依賴裝配,bean的初始化,bean的方法呼叫,bean的銷燬回收”。那問題來了,Spring為什麼能夠準確無誤

Spring能工巧匠們對註解的“加持”

問題的描述與方案的提出在Spring從XML轉向註解時,為了自身的開發方便,對註解含義進行了擴充(具體參考本號上一篇文章)。這個擴充直接導致了一個問題,就是需要從註解往元註解以及元元註解(即沿著從下向上的方向)裡傳遞資料。為了更好的描述這個問題,請再看個示例:@interface A {&

SpringSpringBoot和Spring到底有沒有本質的不同?

現在的Spring相關開發都是基於SpringBoot的。最後在打包時可以把所有依賴的jar包都打進去,構成一個獨立的可執行的jar包。如下圖13: 使用java -jar命令就可以執行這個獨立的jar包。如下圖14: 這個jar包的執行入口就是一個main函式,典型的格式如下: @Spri

Spring負責bean定義註冊的兩個“排頭兵”

別看Spring現在玩的這麼花,其實它的“籌碼”就兩個,“容器”和“bean定義”。只有先把bean定義註冊到容器裡,後續的一切可能才有可能成為可能。所以在進階的路上如果要想走的順暢些,徹底搞清楚bean定義註冊的所有細節至關重要。畢竟這

SpringSpringBoot輕鬆取勝bean定義註冊的“第一階段”

上一篇文章強調了bean定義註冊佔Spring應用的半壁江山。而且詳細介紹了兩個重量級的註冊bean定義的類。今天就以SpringBoot為例,來看看整個SpringBoot應用的bean定義是如何註冊進容器的。先來看看經典的啟動入口,如下圖01: 可以看到呼叫的是run方法,並把主類(main或pr

SpringSpringBoot發起bean定義註冊的“二次攻堅戰”

上一篇文章整體非常輕鬆,因為在容器啟動前,只註冊了一個bean定義,就是SpringBoot的主類。OK,今天接著從容器的啟動入手,找出剩餘所有的bean定義的註冊過程。具體細節肯定會頗為複雜,同樣,大家只需關注都幹了什麼,不用考慮如何幹的。來巨集觀的看下容器的啟動過程,即refresh方法,如下圖01:

Spring註解之王@Configuration和它的一眾“小弟們”

其實對Spring的瞭解達到一定程度後,你就會發現,無論是使用Spring框架開發的應用,還是Spring框架本身的開發都是圍繞著註解構建起來的。空口無憑,那就說個最普通的例子吧。在Spring中要啟用一項XXX功能,標準做法就是用@EnableXXX這種“啟用”型別的註解。那麼這種型

Springbean工廠後處理器的呼叫規則

上一篇文章介紹了對@Configuration類的處理邏輯,這些邏輯都寫在ConfigurationClassPostProcessor類中。 這個類不僅是一個“bean工廠後處理器”,還是一個“bean定義註冊後處理器”。這其實是兩個介面,它們都是來操作be

Spring詳細解說bean後處理器

一個小小的里程碑首先感謝能看到本文的朋友,感謝你的一路陪伴。如果每篇都認真看的話,會發現本系列以bean定義作為切入點,先是詳細解說了什麼是bean定義,接著又強調了bean定義為什麼如此重要。然後又講了獲取bean定義詳細資訊的方法,接著又講了bean定義註冊的若干種方式,然後是bean定義註冊方式的實現細

Spring對@PostConstruct和@PreDestroy註解的處理方法

在bean的例項化過程中,也會用到一系列的相關注解。如@PostConstruct和@PreDestroy用來標記初始化和銷燬方法。平常更多的是側重於應用,很少會有人去了解它背後發生的事情。今天就來看下它們的原始碼,這樣它們對你來說就不再是黑盒子了,而且學習原始碼對每個技術人來說都是必經之路。人們對事物的認知

Spring對@Resource註解的處理方法

@Resource是Java的註解,表示一個資源,它具有雙向的含義,一個是從外部獲取一個資源,一個是向外部提供一個資源。這其實就對應於Spring的注入和註冊。當它用在欄位和方法上時,表示前者。當它用在類上時表示後者。Spring只提供了對前者的支援。該註解本身表示的是資源,資源的含義是很寬泛的。由於絕大部分

Spring對@Autowired和@Value註解的處理方法

在Spring中能夠完成依賴注入的註解有JavaSE提供的@Resource註解,就是上一篇文章介紹的。還有JavaEE提供的@javax.inject.Inject註解,這個用的很少,因為一般都不會去引用JavaEE的jar包。程式設計新說注:JavaEE早已經被Oracle拋棄了。JavaEE這個名字已經

Spring真沒想到,三十步才能完成一個bean例項的建立

在容器啟動快完成時,會把所有的單例bean進行例項化,也可以叫做預先例項化。這樣做的好處之一是,可以及早地發現問題,及早的丟擲異常,及早地解決掉。本文就來看下整個的例項化過程。其實還是比較繁瑣的。一、從容器中找出所有的bean定義名稱因為不知道誰是單例bean,所以只能先全部找出來。如下圖01: 二、

Spring關於@Scheduled定時任務的思考與探索,結果尷尬了

非Spring風格的程式碼與Spring的結合現在的開發都是基於Spring的,所有的依賴都有Spring管理,這沒有問題。但是要突然寫一些非Spring風格的程式碼時,可能會很不習慣,如果還要和Spring風格的程式碼結合起來的話,就會稍顯麻煩。因為非Spring風格的程式碼不由Spring管理,所以Spr

Springjar包詳解

bsp bject 表達 title node unit 調度 緩存 support org.springframework.aop ——Spring的面向切面編程,提供AOP(面向切面編程)的實現 org.springframework.asm——spring 2.

Spring使用Spring AOP時,如何獲取目標方法上的註解

cati 相關操作 config 使用 ide bject poi 註解 except 當使用spring AOP時,判斷目標方法上的註解進行相關操作,如緩存,認證權限等 自定義註解 package com.agent.annotation; import ja

1. Spring入門

1. Spring:入門 Spring是控制反轉(IOC)和麵向切面(AOP)框架 優點: 低侵入式的 DI有效降低耦合 AOP集中管理 ORM和DAO簡化對資料庫的訪問 核心模組 核心容器: 工廠

5. Spring簡化Spring XML配置

5. Spring:簡化Spring XML配置 總覽 自動裝配Bean的屬性 有助於減少和消除property,constructor argument等元素 基於註解的配置