spring原始碼學習筆記1——決議xml生成BeanDefinition的程序決議
一丶Spring決議Xml生成BeanDefinition的流程
1.指定xml路徑
決議xml首先需要知道xml的位置,如下我們構造了ApplicationContext
ApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");

首先根據setConfigLocations方法設定組態檔位置,從這里我們知道Spring支持多個組態檔一起加載
2.構建BeanFactory
生成的BeanDefinition需要放到BeanFactory中,所有在決議之前先生成BeanFactory


這里注釋表示會通知子類重繪BeanFactory,這個子類是指AbstractApplicationContext的子類,這里子類是指AbstractRefreshableApplicationContext(ClassPathXmlApplicationContext的父類,但是refreshBeanFactory在父類中進行了實作)

3.決議xml生成BeanDefinition

這里引入一個新的概念,BeanDefinitionReader,這是Spring對BeanDefinition讀取提供的規范介面,Spring支持基于注解和基于配置生成BeanDefinitiond的不同方式,所有抽取出BeanDefinitionReader,BeanDefinitionReader負責根據資源生成BeanDefinition并且注解到BeanDefinitionRegistry

決議Document生成BeanDefinition并且注冊的操作委托給BeanDefinitionDocumentReader的實作類DefaultBeanDefinitionDocumentReader進行
1.判斷當前xml的profile是否需要加載
如果是默認的Namespace(指xmlns=http://www.springframework.org/schema/beans)讀取profile (多個環境生效的xml 可以使用 【,;】進行分割,還可以使用【!】表示不在哪個環境下生效,比如!dev表示dev環境下這個xml中的bean將不被注入)

這里會先拿組態檔中的spring.profiles.active,如果不支持那么不處理這個xml,如果spring.profiles.active對于的值是空,那么拿spring.profiles.default中指定的配置,如果也不支持當前環境 那么不處理當前xml
2.決議xml生成BeanDefinition

接下來我們看下是怎么決議每一個<bean></bean>生成BeanDefinition的

- 決議Import標簽

對于這種內容,會針對resource的內容決議成Resouce再此呼叫決議成xml生成Bean的方法——loadBeanDefinitions,存在一點點邏輯就是可以當前絕對路徑,url,相對路徑去決議resouce中內容
-
決議alias標簽

為Bean配置別名
根本上都是向BeanFactory注冊,資料維護在aliasMap屬性中,這里存在邏輯,如果name和alias相同會進行洗掉(因為name是bean標簽指定的bean名稱,別名也是這個的話那么沒有必要注冊(直接可以通過bean名稱拿到bean)),還會檢查是否存在別名的回圈參考,對于name=a alias=b 和name=b,alias=a 這種情況會拋出例外
-
決議Bean標簽
見剩余章節
-
決議Beans標簽
回圈處理里面每一個Bean標簽內容
二丶決議<Bean>生成BeanDefinition

1,BeanDefinitionParserDelegate決議Bean標簽生成BeanDefinitionHolder
BeanDefinitionHolder是BeanDefinition的包裝器,里面持有BeanDefinition和Bean的別名,Bean名稱,并且記錄元資料的來源
1.1獲取BeanName 和Bean別名

id是bean的唯一表示,name可以使用,;分割來表示別名,如果沒有指定id,那么beanName默認使用name屬性中的第一個=>a,;b,;cbeanName是a,還會檢查BeanName是否重復
-
決議其他屬性生成BeanDefinition
-
首先會拿class 和 parent指定的內容
!

Parent標簽允許子類對一些屬性不進行值的指定,而是直接使用父類中指定的值 相當于parent 可以起到模板的作用
-
1.2決議scope,abstract,lazy-init,autowire等標簽
-
abstract的作用:
ApplicationContext會預實體化所有singleton的bean,因此很重要的一點是:如果你只想把一個(父)bean定義當作模板使用,而它又指定了class屬性,那么你就得將'abstract'屬性設定為'true'
-
autowire的作用
這里并不是立即進行依賴注入,只是對autowire的值進行決議,后續創建物件的時候才會依據值的不同有不同的行為

-
scope的作用
- Singleton :一個Spring 容器中只有一個Bean 的實體,此為Spring 的默認配置,全容器共享一個實體,
- Prototype :每次呼叫新建一個Bean 的實體,
- Request: Web 專案中,給每一個http request 新建一個Bean 實體,
- Session: Web 專案中,給每一個http session 新建一個Bean 實體,
- Global Session :這個只在portal 應用中有用,給每一個global http session 新建一個Bean實體,
-
lazy-init
lazy-init屬性用于配置當前的springbean是否延遲加載,所謂延遲加載就是創建spring容器的時候是不創建物件的,當第一次獲取該物件時才會實體化該物件
如下可以指定整個xml 是否延遲加載
!

-
depends-on
depends-on表現情況就是:如果A 的depends-on配置的是B,則spring會在創建A之前先創建B,會在銷毀B之前先下回A,
- autowire-candidate
autowire-candidate:設定當前bean在被其他物件作為自動注入物件的時候,是否作為候選bean,默認值是true
-
primary
spring為我們注入bean的時候,如果存在型別相同的多個bean,如介面Service存在實作類A和B,但是A指定了Primary=true 那么會優先注入A
-
init-method
初始化方法,會在實體化bean之后被回呼
-
destroy-method
銷毀方法,Bean被銷毀的時候被回呼使用
-
factory-method
factory-method表示使用當前描述的方法指定創建bean的方法,
factory-bean用于指定自己定義的類,factory-method用于指定創建bean的方法,另外創建物件的方法可以是靜態的也可以是實體的,
1.4 meta 標簽
meta 所宣告的 key 并不會在 Bean 中體現,只是一個額外的宣告,當我們需要使用里面的資訊時,通過 BeanDefinition 的 getAttribute() 獲取,
1.5 lookup-method 標簽
lookup-method 可以將定義bean的方法替換成另外一個bean中的方法
Spring框架通過使用CGLIB庫中的位元組碼生成來動態生成重寫該方法的子類,從而實作這種方法注入
<bean id="期望注入的bean A" >
<lookup-method name="A的某一個方法" bean="替換成Bbean中的方法"/>
</bean>
1.6 replaced-method 標簽
和lookup-method 差不多但是要求替換目標bean實作 MethodReplacer 介面
<bean id="myValueCalculator" >
把myValueCalculator 中的 computeValue 方法使用 replacementComputeValue 替換
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
</bean>
<bean id="replacementComputeValue" />
1.7 constructor-arg 標簽
通過建構式注入,可以通過指定入參的名稱,入參的index,入參的值(ref or value)來注入,還可以指定入參的型別(type屬性)
1.8 property 標簽
通過對應的setter方法注入,通過設定name屬性 指定 欄位的setter方法,使用ref 或者value 來標簽欄位需要注入成什么內容
1.9 qualifier 標簽
qualifier 標簽,和@Qualifier 差不多,qualifier標簽是用來定義需要注入bean的別名的,代表這個bean必須根據名稱(ByName)才會被選為候選bean(一般是ByType),即根據bean的名稱進行注入.
2.注冊BeanDefinition

決議完xml 之后,得到BeanDefinitionHolder,后續使用BeanDefinitionReaderUtils將BeanDefinition注冊到BeanRegistry,在 DefaultListableBeanFactory 底層是使用ConcurrentHashMap 來維護bean名稱和BeanDefinition的關系,別名也是使用ConcurrentHashMap 來維護Bean名稱

2.1 注冊BeanDefinition
DefaultListableBeanFactory 為例子
2.1.1 檢驗是否合法
如果是AbstractBeanDefinition 物件,那么呼叫validate方法
不能同時指定方法重寫 且 指定bean有工廠方法產生,如果指定了重寫但是類中沒有這個方法 也拋出例外
2.1.2 存在相同bean名稱時
如果不允許覆寫BeanDefinition,那么拋出例外,否則覆寫
2.1.3 注冊
維護bean 名稱和 BeanDefinition的map,把Bean名稱加入到beanDefinitionNames 集合中
2.2 注冊 別名
使用ConcurrentHashMap 維護別名和bean的名稱,會檢查是否存在別名回圈的情況,比如A的別名是B,B的別名是A這種情況拋出例外
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/502371.html
標籤:Java
上一篇:MybatisPlus核心功能——實作CRUD增刪改查操作 (包含條件構造器)
下一篇:Mybatis的快取
