目錄
Bean生命周期
階段1:Bean元信息配置階段
Bean信息定義4種方式
API的方式
XML的方式
properties文件的方式
注解的方式
小結(jié)
階段2:Bean元信息解析階段
Bean元信息的解析主要有3種方式
XML方式解析:XmlBeanDefinitionReader
properties文件定義bean的解析: PropertiesBeanDefinitionReader
注解方式:AnnotatedBeanDefinitionReader
階段3:Spring Bean注冊(cè)階段
Bean注冊(cè)接口:BeanDefinitionRegistry
別名注冊(cè)接口:AliasRegistry
DefaultListableBeanFactory類
階段4:BeanDefinition合并階段
案例
階段5:Bean Class加載階段
Bean生命周期
Spring bean 生命周期可以分為13個(gè)階段:
- Bean元信息配置階段
- Bean元信息解析階段
- 將Bean注冊(cè)到容器中
- BeanDefinition合并階段
- Bean Class加載階段
- Bean實(shí)例化階段(2個(gè)小階段)
- Bean實(shí)例化前階段
- Bean實(shí)例化階段
- 合并后的BeanDefinition處理
- 屬性賦值階段(3個(gè)小階段)
- Bean實(shí)例化后階段
- Bean屬性賦值前階段
- Bean屬性賦值階段
- Bean初始化階段(4個(gè)小階段)
- Bean Aware接口回調(diào)階段
- Bean初始化前階段
- Bean初始化階段
- Bean初始化后階段
- 所有單例bean初始化完成后階段
- Bean的使用階段
- Bean銷毀前階段
- Bean銷毀階段
階段1:Bean元信息配置階段
這個(gè)階段主要就是bean信息的定義
Bean信息定義4種方式
- API的方式
- Xml文件方式
- properties文件的方式
- 注解的方式
API的方式
先來(lái)說(shuō)這種方式,因?yàn)槠渌麕追N方式最終都會(huì)轉(zhuǎn)化為這種方式來(lái)定義bean配置信息。
Spring容器啟動(dòng)的過(guò)程中,會(huì)將Bean解析成Spring內(nèi)部的BeanDefinition結(jié)構(gòu)。 不管是是通過(guò)xml配置文件的標(biāo)簽,還是通過(guò)注解配置的 @Bean ,還是 @Compontent 標(biāo)注的類,還是掃描得到的類等,它最終都會(huì)被解析成一個(gè)BeanDefinition對(duì)象,最后我們的Bean工廠就會(huì)根據(jù)這份Bean的定義信 息,對(duì)bean進(jìn)行實(shí)例化、初始化等等操作。
你可以把BeanDefinition丟給Bean工廠,然后Bean工廠就會(huì)根據(jù)這個(gè)信息幫你生產(chǎn)一個(gè)Bean實(shí)例,拿去使用。 BeanDefinition里面里面包含了bean定義的各種信息,如:bean對(duì)應(yīng)的class、scope、lazy信息、 dependOn信息、autowireCandidate(是否是候選對(duì)象)、primary(是否是主要的候選者)等信息。
BeanDefinition是個(gè)接口,有幾個(gè)實(shí)現(xiàn)類,看一下類圖:
BeanDefinition接口
bean定義信息的接口,我們下來(lái)看看源碼:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
/**
*singleton
*/
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
/**
* prototype
*/
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
// Modifiable attributes
/**
* 設(shè)置此bean的父bean名稱(對(duì)應(yīng)xml中bean元素的parent屬性)
*/
void setParentName(@Nullable String parentName);
/**
* 返回bean定義時(shí)指定的父bean的名稱
*/
@Nullable
String getParentName();
/**
* 指定bean的全路徑類名(對(duì)應(yīng)xml中的bean的class屬性)
*/
void setBeanClassName(@Nullable String beanClassName);
/**
* 返回此 bean 定義的當(dāng)前 bean 類名。
* 請(qǐng)注意,這不一定是運(yùn)行時(shí)使用的實(shí)際類名,以防子定義覆蓋/繼承其父類的類名。此外,這可能只是
* 調(diào)用工廠方法的類,或者在調(diào)用方法的工廠 bean 引用的情況下它甚至可能是空的。因此,不要認(rèn)為
* 這是運(yùn)行時(shí)確定的 bean 類型,而只是在單個(gè) bean 定義級(jí)別將其用于解析目的
*/
@Nullable
String getBeanClassName();
/**
* 指定bean的范圍(對(duì)應(yīng)xml中bea定義時(shí)的scope屬性)
*/
void setScope(@Nullable String scope);
/**
* 返回bean的范圍
*/
@Nullable
String getScope();
/**
* 設(shè)置是否延遲初始化該bean(對(duì)應(yīng)xml中bean定義時(shí)的lazy屬性)
*/
void setLazyInit(boolean lazyInit);
/**
* 返回該bean是否是一個(gè)延遲初始化的bean(只對(duì)單例的bean有效,因?yàn)槎嗬腷ean肯定是使用時(shí)才會(huì)
* 創(chuàng)建的)
*/
boolean isLazyInit();
/**
* 設(shè)置該bean初始化時(shí)需要依賴的bean的名稱,bean工廠會(huì)保證讓這些bean在該bean之前初始化
*/
void setDependsOn(@Nullable String... dependsOn);
/**
* 返回此bean依賴的bean的名稱
*/
@Nullable
String[] getDependsOn();
/**
* 設(shè)置此bean是否作為其他bean自動(dòng)注入時(shí)的候選者
*/
void setAutowireCandidate(boolean autowireCandidate);
/**
* 返回此bean是否作為其他bean自動(dòng)注入時(shí)的候選者
*/
boolean isAutowireCandidate();
/**
* 設(shè)置此bean是否為自動(dòng)注入的主要候選者
*/
void setPrimary(boolean primary);
/**
* 返回此bean是否作為自動(dòng)注入的主要候選者
*/
boolean isPrimary();
/**
* 指定要使用的工廠bean(如果有)。這是要對(duì)其調(diào)用指定工廠方法的bean的名稱
*/
void setFactoryBeanName(@Nullable String factoryBeanName);
/**
* 返回工廠bean名稱(如果有)(對(duì)應(yīng)xml中bean元素的factory-bean屬性)
*/
@Nullable
String getFactoryBeanName();
/**
*
* 指定工廠方法(如果有)。此方法將使用構(gòu)造函數(shù)參數(shù)調(diào)用,如果未指定任何參數(shù),則不使用任何參
* 數(shù)調(diào)用。該方法將在指定的工廠bean(如果有的話)上調(diào)用,或者作為本地bean類上的靜態(tài)方法調(diào)
* 用。
*/
void setFactoryMethodName(@Nullable String factoryMethodName);
/**
* 返回工廠方法名稱(對(duì)應(yīng)xml中bean的factory-method屬性)
*/
@Nullable
String getFactoryMethodName();
/**
* 返回此bean的構(gòu)造函數(shù)參數(shù)值
*/
ConstructorArgumentValues getConstructorArgumentValues();
/**
* 是否有構(gòu)造器參數(shù)值設(shè)置信息(對(duì)應(yīng)xml中bean元素的<constructor-arg />子元素)
*/
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
/**
* 獲取bean定義時(shí)配置的屬性值設(shè)置信息
*/
MutablePropertyValues getPropertyValues();
/**
* 這個(gè)bean定義中是否有屬性設(shè)置信息(對(duì)應(yīng)xml中bean元素的<property />子元素)
*/
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
/**
* 設(shè)置bean初始化方法名稱
*/
void setInitMethodName(@Nullable String initMethodName);
/**
* 返回bean初始化方法名稱
*/
@Nullable
String getInitMethodName();
/**
* 設(shè)置bean銷毀方法的名稱
*/
void setDestroyMethodName(@Nullable String destroyMethodName);
/**
* 返回bean銷毀方法的名稱
*/
@Nullable
String getDestroyMethodName();
/**
* 為此BeanDefinition設(shè)置角色提示。角色提示為框架和工具提供了特定BeanDefinition的角色和重
* 要性的指示
*/
void setRole(int role);
/**
* 獲取此BeanDefinition的角色提示。角色提示為框架和工具提供了特定BeanDefinition的角色和重
* 要性的指示
*/
int getRole();
/**
* 設(shè)置bean的描述信息
*/
void setDescription(@Nullable String description);
/**
* 返回Bean的描述信息
*/
@Nullable
String getDescription();
// Read-only attributes
/**
* 返回此 bean 定義的可解析類型
*/
ResolvableType getResolvableType();
/**
* 是否是單例
*/
boolean isSingleton();
/**
* 是否是多例
*/
boolean isPrototype();
/**
* 返回此 bean 是否是“抽象的”,即不打算實(shí)例化
*/
boolean isAbstract();
/**
* 返回此bean定義來(lái)自的資源的描述(以便在出現(xiàn)錯(cuò)誤時(shí)顯示上下文)
*/
@Nullable
String getResourceDescription();
/**
* 返回原始 BeanDefinition,如果沒有則返回null
*/
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
另外,BeanDefinition還實(shí)現(xiàn)了兩個(gè)接口:
-
AttributeAccessor
-
BeanMetadataElement
AttributeAccessor接口:屬性訪問接口
源碼:
public interface AttributeAccessor {
/**
* 設(shè)置 屬性->值 鍵值對(duì)
*/
void setAttribute(String name, @Nullable Object value);
/**
* 獲取某個(gè)屬性對(duì)應(yīng)的值
*/
@Nullable
Object getAttribute(String name);
/**
* 移除某個(gè)屬性
*/
@Nullable
Object removeAttribute(String name);
/**
* 是否包含某個(gè)屬性
*/
boolean hasAttribute(String name);
/**
* 列出所有屬性
*/
String[] attributeNames();
}
這個(gè)接口相當(dāng)于key->value數(shù)據(jù)結(jié)構(gòu)的一種操作,BeanDefinition繼承這個(gè),內(nèi)部實(shí)際上是使用了 LinkedHashMap來(lái)實(shí)現(xiàn)這個(gè)接口中的所有方法,通常我們通過(guò)這些方法來(lái)保存BeanDefinition定義過(guò)程中產(chǎn)生的一些附加信息。
BeanMetaDataElement接口
public interface BeanMetadataElement {
@Nullable
default Object getSource() {
return null;
}
BeanDefinition繼承這個(gè)接口,getSource返回BeanDefinition定義的來(lái)源,比如我們通過(guò)xml定義 BeanDefinition的,此時(shí)getSource就表示定義bean的xml資源;若我們通過(guò)api的方式定義 BeanDefinition,我們可以將source設(shè)置為定義BeanDefinition時(shí)所在的類,出錯(cuò)時(shí),可以根據(jù)這個(gè)來(lái)源方便排錯(cuò)。
RootBeanDefinition類:表示根bean定義信息
通常bean中沒有父bean的就使用這種表示。
ChildBeanDefinition類:表示子bean定義信息
如果需要指定父bean的,可以使用ChildBeanDefinition來(lái)定義子bean的配置信息,里面有個(gè) parentName 屬性,用來(lái)指定父bean的名稱。
GenericBeanDefinition類:通用的bean定義信息
既可以表示沒有父bean的bean配置信息,也可以表示有父bean的子bean配置信息,這個(gè)類里面也有 parentName屬性,用來(lái)指定父bean的名稱。?
ConfigurationClassBeanDefinition類:表示通過(guò)配置類中@Bean方法定義 bean信息?
可以通過(guò)配置類中使用@Bean來(lái)標(biāo)注一些方法,通過(guò)這些方法來(lái)定義bean,這些方法配置的bean信息最后會(huì)轉(zhuǎn)換為ConfigurationClassBeanDefinition類型的對(duì)象。
AnnotatedBeanDefinition接口:表示通過(guò)注解的方式定義的bean信息
里面有個(gè)方法getMetadata()用來(lái)獲取定義這個(gè)bean的類上的所有注解信息。
BeanDefinitionBuilder:構(gòu)建BeanDefinition的工具類?
spring中為了方便操作BeanDefinition,提供了一個(gè)類: BeanDefinitionBuilder ,內(nèi)部提供了很多 靜態(tài)方法,通過(guò)這些方法可以非常方便的組裝BeanDefinition對(duì)象。
案例1:組裝一個(gè)簡(jiǎn)單的bean
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
@Test
void test1() {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
System.out.println(beanDefinition);
}
運(yùn)行輸出:
Root bean: class [com.example.User]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
案例2:組裝一個(gè)有屬性的bean?
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
@Test
void test2(){
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
//給該bean的name屬性設(shè)置值
beanDefinitionBuilder.addPropertyValue("name","張三");
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
System.out.println(beanDefinition);
System.out.println("---------------------");
//創(chuàng)建一個(gè)Spring容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//將該Bean注冊(cè)到Spring容器中
beanFactory.registerBeanDefinition("User",beanDefinition);
//獲取容器中的Bean
User user = (User) beanFactory.getBean("User");
System.out.println(user);
}
運(yùn)行輸出:
Root bean: class [com.example.User]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
---------------------
User{name='張三'}
案例3:組裝一個(gè)有依賴關(guān)系的bean
public class User {
private String name;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", car=" + car +
'}';
}
}
public class Car {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
'}';
}
}
@Test
void test3(){
//創(chuàng)建Car對(duì)象,并為其賦值
BeanDefinitionBuilder beanDefinitionBuilder2 = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
beanDefinitionBuilder2.addPropertyValue("name","寶馬");
AbstractBeanDefinition CarBeanDefinition = beanDefinitionBuilder2.getBeanDefinition();
//創(chuàng)建User對(duì)象,并為其賦值
BeanDefinitionBuilder beanDefinitionBuilder1 = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
beanDefinitionBuilder1.addPropertyValue("name","張三");
beanDefinitionBuilder1.addPropertyReference("car","car");//為該bean注入依賴的bean
AbstractBeanDefinition UserBeanDefinition = beanDefinitionBuilder1.getBeanDefinition();
//創(chuàng)建Spring容器,將這兩個(gè)Bean注冊(cè)到容器中
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("user",UserBeanDefinition);
beanFactory.registerBeanDefinition("car",CarBeanDefinition);
Car car = (Car) beanFactory.getBean("car");
System.out.println(car);
User user = (User) beanFactory.getBean("user");
System.out.println(user);
}
運(yùn)行輸出:
Car{name='寶馬'}
User{name='張三', car=Car{name='寶馬'}}
案例4:有父子關(guān)系的bean
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
@Test
void test4(){
//創(chuàng)建一個(gè)bean
BeanDefinitionBuilder beanDefinitionBuilder1 = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
beanDefinitionBuilder1.addPropertyValue("name","張三");
AbstractBeanDefinition UserBeanDefinition = beanDefinitionBuilder1.getBeanDefinition();
//再創(chuàng)建一個(gè)bean,指定該bean的父bean,這樣該bean就擁有了父bean的所有屬性
BeanDefinitionBuilder beanDefinitionBuilder2 = BeanDefinitionBuilder.childBeanDefinition("user");
AbstractBeanDefinition UserBeanDefinitionSon = beanDefinitionBuilder2.getBeanDefinition();
//將兩個(gè)bean都注冊(cè)到容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("user",UserBeanDefinition);
beanFactory.registerBeanDefinition("userSon",UserBeanDefinitionSon);
User user = (User) beanFactory.getBean("user");
System.out.println(user);
User userSon = (User) beanFactory.getBean("userSon");
System.out.println(userSon);
}
運(yùn)行輸出:
User{name='張三'}
User{name='張三'}
注意:
- 有父子關(guān)系的時(shí)候,我們的 子 創(chuàng)建的不再是rootBeanDifinition對(duì)象了,而是childBeanDefinition對(duì)象,或者genericBeanDefinition對(duì)象,因?yàn)橹挥兴麄儍?nèi)部才有指定父bean的方法
- 我們知道,一個(gè)bean指定了父bean以后,該bean會(huì)擁有父bean的所有屬性。但是我們?cè)傧胍幌?,子bean擁有了父bean的所有屬性,那屬性值呢?這些屬性會(huì)有值嗎?我們?cè)倏纯瓷厦娴妮敵?,默認(rèn)情況下子bean也擁有了相同的值。又有一個(gè)疑問,那我們可以為子bean的屬性再賦值來(lái)覆蓋之前的值嗎,答案是可以的,如圖:
案例5:通過(guò)api設(shè)置(Map、Set、List)屬性
?主要是用到這幾個(gè)對(duì)象:
- ManagedList
- ManagedSet
- ManagedMap
- ManagedProperties
- RuntimeBeanReference(很重要?。。。?/span>
public class Car {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
'}';
}
}
public class UserObj {
private String name;
private Integer salary;
private Car car;
private List<String> stringList;
private List<Car> carList;
private Set<String> stringSet;
private Set<Car> carSet;
private Map<String,String> stringMap;
private Map<String,Car> stringCarMap;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSalary() {
return salary;
}
public void setSalary(Integer salary) {
this.salary = salary;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public List<String> getStringList() {
return stringList;
}
public void setStringList(List<String> stringList) {
this.stringList = stringList;
}
public List<Car> getCarList() {
return carList;
}
public void setCarList(List<Car> carList) {
this.carList = carList;
}
public Set<String> getStringSet() {
return stringSet;
}
public void setStringSet(Set<String> stringSet) {
this.stringSet = stringSet;
}
public Set<Car> getCarSet() {
return carSet;
}
public void setCarSet(Set<Car> carSet) {
this.carSet = carSet;
}
public Map<String, String> getStringMap() {
return stringMap;
}
public void setStringMap(Map<String, String> stringMap) {
this.stringMap = stringMap;
}
public Map<String, Car> getStringCarMap() {
return stringCarMap;
}
public void setStringCarMap(Map<String, Car> stringCarMap) {
this.stringCarMap = stringCarMap;
}
@Override
public String toString() {
return "UserObj{" +
"name='" + name + '\'' +
", salary=" + salary +
", car=" + car +
", stringList=" + stringList +
", carList=" + carList +
", stringSet=" + stringSet +
", carSet=" + carSet +
", stringMap=" + stringMap +
", stringCarMap=" + stringCarMap +
'}';
}
}
@Test
void test5(){
BeanDefinitionBuilder beanDefinitionBuilder1 = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
beanDefinitionBuilder1.addPropertyValue("name","奧迪");
AbstractBeanDefinition beanDefinition1 = beanDefinitionBuilder1.getBeanDefinition();
BeanDefinitionBuilder beanDefinitionBuilder2 = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
beanDefinitionBuilder2.addPropertyValue("name","寶馬");
AbstractBeanDefinition beanDefinition2 = beanDefinitionBuilder2.getBeanDefinition();
ManagedList<String> stringList = new ManagedList<>();
stringList.addAll(Arrays.asList("test1","test2","test3"));
ManagedList<RuntimeBeanReference> carList = new ManagedList<>();
carList.add(new RuntimeBeanReference("car1"));
carList.add(new RuntimeBeanReference("car2"));
ManagedSet<String> stringSet = new ManagedSet<>();
stringSet.addAll(Arrays.asList("test1","test2","test3"));
ManagedSet<RuntimeBeanReference> carSet = new ManagedSet<>();
carSet.add(new RuntimeBeanReference("car1"));
carSet.add(new RuntimeBeanReference("car2"));
ManagedMap<String, String> stringMap = new ManagedMap<>();
stringMap.put("測(cè)試1","test1");
stringMap.put("測(cè)試2","test2");
stringMap.put("測(cè)試3","test3");
ManagedMap<String, RuntimeBeanReference> stringCarMap = new ManagedMap<>();
stringCarMap.put("car1",new RuntimeBeanReference("car1"));
stringCarMap.put("car2",new RuntimeBeanReference("car2"));
BeanDefinitionBuilder beanDefinitionBuilder3 = BeanDefinitionBuilder.rootBeanDefinition(UserObj.class.getName());
beanDefinitionBuilder3.addPropertyValue("name","張三");
beanDefinitionBuilder3.addPropertyValue("salary",50000);
beanDefinitionBuilder3.addPropertyValue("stringList",stringList);
beanDefinitionBuilder3.addPropertyValue("carList",carList);
beanDefinitionBuilder3.addPropertyValue("stringSet",stringSet);
beanDefinitionBuilder3.addPropertyValue("carSet",carSet);
beanDefinitionBuilder3.addPropertyValue("stringMap",stringMap);
beanDefinitionBuilder3.addPropertyValue("stringCarMap",stringCarMap);
AbstractBeanDefinition beanDefinition3 = beanDefinitionBuilder3.getBeanDefinition();
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("car1",beanDefinition1);
factory.registerBeanDefinition("car2",beanDefinition2);
factory.registerBeanDefinition("UserObj",beanDefinition3);
System.out.println(factory.getBean("car1"));
System.out.println(factory.getBean("car2"));
System.out.println(factory.getBean("UserObj"));
}
運(yùn)行輸出:
Car{name='奧迪'}
Car{name='寶馬'}
UserObj{name='張三', salary=50000, car=null, stringList=[test1, test2, test3], carList=[Car{name='奧迪'}, Car{name='寶馬'}], stringSet=[test1, test2, test3], carSet=[Car{name='奧迪'}, Car{name='寶馬'}], stringMap={測(cè)試1=test1, 測(cè)試2=test2, 測(cè)試3=test3}, stringCarMap={car1=Car{name='奧迪'}, car2=Car{name='寶馬'}}}
XML的方式
我們一開始學(xué)spring的時(shí)候使用的就是這種方式,已經(jīng)很熟悉了,這里不做贅述
properties文件的方式
這種方式很陌生,將bean定義信息放在properties文件中,然后通過(guò)解析器將配置信息解析為BeanDefinition對(duì)象。
employee.(class)=MyClass // 等同于:<bean class="MyClass" />
employee.(abstract)=true // 等同于:<bean abstract="true" />
employee.group=Insurance // 為屬性設(shè)置值,等同于:<property name="group" value="Insurance" />
employee.usesDialUp=false // 為employee這個(gè)bean中的usesDialUp屬性設(shè)置值,等同于:<property name="usesDialUp" value="false" />
salesrep.(parent)=employee // 定義了一個(gè)id為salesrep的bean,指定父bean為employee,等同于:<bean id="salesrep" parent="employee" />
salesrep.(lazy-init)=true // 設(shè)置延遲初始化,等同于:<bean lazy-init="true" />
salesrep.manager(ref)=tony // 設(shè)置這個(gè)bean的manager屬性值,是另外一個(gè)bean,名稱為tony,等同于:<property name="manager" ref="tony" />
salesrep.department=Sales // 等同于:<property name="department" value="Sales" />
techie.(parent)=employee // 定義了一個(gè)id為techie的bean,指定父bean為employee,等同于:<bean id="techie" parent="employee" />
techie.(scope)=prototype // 設(shè)置bean的作用域,等同于<bean scope="prototype" />
techie.manager(ref)=jeff // 等同于:<property name="manager" ref="jeff" />
techie.department=Engineering // <property name="department" value="Engineering" />
techie.usesDialUp=true // <property name="usesDialUp" value="true" />
ceo.$0(ref)=secretary // 設(shè)置構(gòu)造函數(shù)第1個(gè)參數(shù)值,等同于:<constructor-arg index="0" ref="secretary" />
ceo.$1=1000000 // 設(shè)置構(gòu)造函數(shù)第2個(gè)參數(shù)值,等同于:<constructor-arg index="1" value="1000000" />
注解的方式
對(duì)于注解的方式注冊(cè)bean的話,常見的就是@Component和@Bean了,這里也不做贅述了。
小結(jié)
不管是那一種方式注冊(cè)bean,最終都是會(huì)解析成一個(gè)BeanDefinition對(duì)象。
階段2:Bean元信息解析階段
Bean元信息的解析就是將各種方式定義的bean配置信息解析為BeanDefinition對(duì)象
Bean元信息的解析主要有3種方式
- 解析xml方式定義的bean
- 解析properties文件定義的bean
- 解析注解方式定義的bean
XML方式解析:XmlBeanDefinitionReader
spring中提供了一個(gè)類 XmlBeanDefinitionReader ,將xml中定義的bean解析為BeanDefinition對(duì) 象。?
案例:
public class Car {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
'}';
}
}
public class User {
private String name;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", car=" + car +
'}';
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="car" class="com.example.Car">
<property name="name" value="寶馬"></property>
</bean>
<bean id="car1" class="com.example.Car">
<property name="name" value="奧迪"></property>
</bean>
<bean id="car2" parent="car1"></bean>
<bean id="user" class="com.example.User">
<property name="name" value="張三"></property>
<property name="car" ref="car2"></property>
</bean>
</beans>
@Test
public void test1(){
//創(chuàng)建一個(gè)spring容器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//定義一個(gè)xml方式的bean的讀取器,需要傳入一個(gè)bean的注冊(cè)器
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(factory);
//根據(jù)xml文件的位置解析定義的bean,并將其注冊(cè)到我們上面指定的spring容器中
String location="applicationContext.xml";
xmlBeanDefinitionReader.loadBeanDefinitions(location);
for (String beanName:factory.getBeanDefinitionNames()){
System.out.println(beanName+"===>"+factory.getBean(beanName));
}
}
運(yùn)行輸出:
car===>Car{name='寶馬'}
car1===>Car{name='奧迪'}
car2===>Car{name='奧迪'}
user===>User{name='張三', car=Car{name='奧迪'}}
properties文件定義bean的解析: PropertiesBeanDefinitionReader
spring中提供了一個(gè)叫PropertiesBeanDefinitionReader的類,將properties中定義的bean解析為一個(gè)BeanDefinition對(duì)象
案例:
car.(class)=com.example.Car
car.name=奧迪
car1.(class)=com.example.Car
car1.name=寶馬
car2.(parent)=car1
user.(class)=com.example.User
user.name=張三
user.car(ref)=car
@Test
public void test2(){
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
PropertiesBeanDefinitionReader propertiesBeanDefinitionReader = new PropertiesBeanDefinitionReader(beanFactory);
String location="applicationContext.properties";
propertiesBeanDefinitionReader.loadBeanDefinitions(location);
for (String beanName:beanFactory.getBeanDefinitionNames()){
System.out.println(beanName+"===>"+beanFactory.getBean(beanName));
}
}
運(yùn)行輸出:
user===>User{name='張三', car=Car{name='寶馬'}}
car1===>Car{name='奧迪'}
car===>Car{name='寶馬'}
car2===>Car{name='寶馬'}
其實(shí)解析的方式也和xml差不多,只是換成了對(duì)應(yīng)的類來(lái)解析bean而已。
注解方式:AnnotatedBeanDefinitionReader
@Primary
public class Car {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
'}';
}
}
@Lazy
public class User {
@Autowired
private Car car;
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "User{" +
"car=" + car +
'}';
}
}
@Test
public void test3(){
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(factory);
annotatedBeanDefinitionReader.register(Car.class,User.class);
for (String beanName:factory.getBeanDefinitionNames()){
System.out.println(beanName+"===>"+ factory.getBean(beanName));
}
}
運(yùn)行輸出:
car===>Car{name='null'}
user===>User{car=null}
注意:
- 我們所說(shuō)的注解的解析方式,用到了AnnotatedBeanDefinitionReader類來(lái)解析
- 千萬(wàn)千萬(wàn)別理解錯(cuò)了,并不是說(shuō)要在類上加上@Component注解,才能通過(guò)AnnotatedBeanDefinitionReader類來(lái)解析這個(gè)類。其實(shí)@Component注解就沒啥用,相當(dāng)于一個(gè)標(biāo)識(shí)符,就是默認(rèn)情況下看到@Component標(biāo)注的注解以后,spring就認(rèn)為我們要解析這個(gè)類為一個(gè)bean并放到spring容器中
- 可以看到案例里面,注解和xml或者properties方式的解析略有不同,xml或者properties方式是用到了一個(gè)叫l(wèi)oadBeanDefinitions()的方法,然后傳入文件所在位置。而注解解析的方式是用到了register()方法,傳入的參數(shù)是需要的類,且是一個(gè)可變參數(shù)。
- 根據(jù)輸出,我們可以看到user里面的car為空,為什么?。棵髅魑覀円呀?jīng)用@Autowired注入了啊,這個(gè)疑問后面再來(lái)解答
階段3:Spring Bean注冊(cè)階段
bean注冊(cè)階段需要用到一個(gè)非常重要的接口:BeanDefinitionRegistry?
Bean注冊(cè)接口:BeanDefinitionRegistry
該接口中定義了常用的操作bean的方法
先來(lái)看看這個(gè)接口的源碼:
public interface BeanDefinitionRegistry extends AliasRegistry {
/**
* 注冊(cè)一個(gè)新的beanDefinition
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
/**
* 從容器中移除指定名稱的bean
*/
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* 返回該bean的定義信息
*/
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* 返回容器中是否含有該bean
*/
boolean containsBeanDefinition(String beanName);
/**
* 返回容器中bean的名稱列表
*/
String[] getBeanDefinitionNames();
/**
* 返回容器中bean的數(shù)量
*/
int getBeanDefinitionCount();
/**
* 返回該bean是否被使用。(beanName可以時(shí)名稱或者別名)
*/
boolean isBeanNameInUse(String beanName);
}
別名注冊(cè)接口:AliasRegistry
BeanDefinitionRegistry 接口繼承了 AliasRegistry 接口,這個(gè)接口中定義了操作bean別名的一些 方法,看一下其源碼:
public interface AliasRegistry {
/**
* 為該bean創(chuàng)建一個(gè)別名
*/
void registerAlias(String name, String alias);
/**
* 移除該別名
*/
void removeAlias(String alias);
/**
* 返回該別名是否使用
*/
boolean isAlias(String name);
/**
* 返回別名列表
*/
String[] getAliases(String name);
}
DefaultListableBeanFactory類
該類是BeanDefinitionRegistry的實(shí)現(xiàn)類
我們打開源碼可以看到BeanDefinitionRegistry有很多實(shí)現(xiàn)類,那為什么特別提到了其中的DefaultListableBeanFactory實(shí)現(xiàn)類你,因?yàn)槠渌鼘?shí)現(xiàn)類的內(nèi)部都是轉(zhuǎn)發(fā)給DefaultListableBeanFactory進(jìn)行處理的,所以真正的實(shí)現(xiàn)BeanDefinitionRegistry這個(gè)接口的類是DefaultListableBeanFactory
階段4:BeanDefinition合并階段
可能我們定義bean的時(shí)候有父子bean關(guān)系,此時(shí)子BeanDefinition中的信息是不完整的,比如設(shè)置屬性的時(shí)候配置在父BeanDefinition中,此時(shí)子BeanDefinition中是沒有這些信息的,或者子bean和父bean中都設(shè)置了屬性,那我們此時(shí)的子beanDefinition肯定是不完整的,需要將子bean的 BeanDefinition和父bean的BeanDefinition進(jìn)行合并,如果有沖突的屬性,子bean的屬性會(huì)覆蓋父bean的,經(jīng)過(guò)上面的操作最終就會(huì)得到一個(gè) RootBeanDefinition ,合并之后得到的 RootBeanDefinition 包含bean定義的所有信息,包含了從父bean中繼繼承過(guò)來(lái)的所有信息,后續(xù)bean的所有創(chuàng)建工作就是依靠合并之后BeanDefinition來(lái)進(jìn)行的。 合并BeanDefinition會(huì)使用下面這個(gè)方法:
org.springframework.beans.factory.support.AbstractBeanFactory#getMergedBeanDefin ition
bean定義可能存在多級(jí)父子關(guān)系,合并的時(shí)候進(jìn)進(jìn)行遞歸合并,最終得到一個(gè)包含完整信息的 RootBeanDefinition
案例
public class Course {
private String courseName;
private String description;
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Course{" +
"courseName='" + courseName + '\'' +
", description='" + description + '\'' +
'}';
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="course" class="com.example.Course"></bean>
<bean id="course1" parent="course">
<property name="courseName" value="java"></property>
<property name="description" value="java核心技術(shù)課程"></property>
</bean>
<bean id="course2" parent="course1">
<property name="description" value="javaWeb課程"></property>
</bean>
</beans>
public class mergeBeanDefinitionTest {
@Test
public void test(){
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String location="applicationContext.xml";
xmlBeanDefinitionReader.loadBeanDefinitions(location);
for (String beanName:beanFactory.getBeanDefinitionNames()){
System.out.println("-------------------------");
System.out.println(beanName);
System.out.println("合并前");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
System.out.println(beanDefinition);
for (PropertyValue property:beanDefinition.getPropertyValues()){
System.out.println(property.getName()+"====>"+property.getValue());
}
//調(diào)用該方法將父子beanDefinition合并,才能讓子的beanDefinition完整
BeanDefinition mergedBeanDefinition = beanFactory.getMergedBeanDefinition(beanName);
System.out.println("合并后");
System.out.println(mergedBeanDefinition);
for (PropertyValue property:mergedBeanDefinition.getPropertyValues()){
System.out.println(property.getName()+"====>"+property.getValue());
}
System.out.println("-------------------------");
}
}
}
?運(yùn)行輸出:
-------------------------
course
合并前
Generic bean: class [com.example.Course]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [applicationContext.xml]
合并后
Root bean: class [com.example.Course]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [applicationContext.xml]
-------------------------
-------------------------
course1
合并前
Generic bean with parent 'course': class [null]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [applicationContext.xml]
courseName====>TypedStringValue: value [java], target type [null]
description====>TypedStringValue: value [java核心技術(shù)課程], target type [null]
合并后
Root bean: class [com.example.Course]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [applicationContext.xml]
courseName====>TypedStringValue: value [java], target type [null]
description====>TypedStringValue: value [java核心技術(shù)課程], target type [null]
-------------------------
-------------------------
course2
合并前
Generic bean with parent 'course1': class [null]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [applicationContext.xml]
description====>TypedStringValue: value [javaWeb課程], target type [null]
合并后
Root bean: class [com.example.Course]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [applicationContext.xml]
courseName====>TypedStringValue: value [java], target type [null]
description====>TypedStringValue: value [javaWeb課程], target type [null]
-------------------------
重點(diǎn)觀察彩色字體部分, course1繼承了course,但course本身就沒有屬性,綠色部分的屬性本身就是course1自己的,所有合并前合并后都有這些屬性并不奇怪。我們?cè)倏纯碿ours2的黃色部分,course2是繼承了course1的,course2本身有一個(gè)description屬性,所以合并之前course2只有一個(gè)description屬性并不奇怪,但是我們看看合并之后,course2有了courseName屬性了,這就是從course1繼承過(guò)來(lái)的屬性,這說(shuō)明了什么?說(shuō)明就是通過(guò)我們調(diào)用了getMergeBeanDefinition()以后,子bean和父bean合并,從而讓我們的子bean擁有完整的beanDefinition信息,驗(yàn)證了上面的說(shuō)法!!!還有一點(diǎn),如果我們?cè)诤喜⑷绻蛴∫幌抡{(diào)用getMergeBeanDefinition方法返回的對(duì)象,就會(huì)發(fā)現(xiàn)該BeanDefinition對(duì)象的類型已經(jīng)從GenericBeanDefinition變?yōu)镽ootBeanDefinition類型了,并且以后操作都是又這個(gè)完整的RootBeanDefinition來(lái)完成。
階段5:Bean Class加載階段
這個(gè)階段就是將bean的class名稱轉(zhuǎn)換為Class類型的對(duì)象
BeanDefinition中有個(gè)Object類型的字段:beanClass
private volatile Object beanClass;
用來(lái)表示bean的class對(duì)象,通常這個(gè)字段的值有2種類型,一種是bean對(duì)應(yīng)的Class類型的對(duì)象,另一 種是bean對(duì)應(yīng)的Class的完整類名,第一種情況不需要解析,第二種情況:即這個(gè)字段是bean的類名的時(shí)候,就需要通過(guò)類加載器將其轉(zhuǎn)換為一個(gè)Class對(duì)象。 此時(shí)會(huì)對(duì)階段4中合并產(chǎn)生的 RootBeanDefinition 中的 beanClass 進(jìn)行解析,將bean的類名轉(zhuǎn)換為 Class對(duì)象 ,然后賦值給 beanClass 字段。?
源碼位置:
org.springframework.beans.factory.support.AbstractBeanFactory#resolveBeanClass文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-435119.html
然后就開始進(jìn)入下面的實(shí)例化這個(gè)對(duì)象的階段了。我們下篇文章繼續(xù)來(lái)看?。?!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-435119.html
到了這里,關(guān)于Spring進(jìn)階(十六)之spring生命周期的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!