Spring bean生命周期12個環(huán)節(jié)
1.階段1:Bean元信息配置階段
2.階段2:Bean元信息解析階段
3.階段3:將Bean注冊到容器中
4.階段4:BeanDefinition合并階段
- 階段5:Bean Class加載階段
-
6.階段6:Bean實例化階段(2個小階段)
- Bean實例化前階段
- Bean實例化階段
- 階段7:合并后的BeanDefinition處理
-
- 階段8:屬性賦值階段(3個小階段)
- Bean實例化后階段
- Bean屬性賦值前階段
- Bean屬性賦值階段
-
9.階段9:Bean初始化階段(4個小階段)
- Bean Aware接口回調(diào)階段
- Bean初始化前階段
- Bean初始化階段
- Bean初始化后階段
10.階段10:所有單例bean初始化完成后階段
- 階段11:Bean的使用階段
12.階段12:Bean銷毀前階段
- 階段13:Bean銷毀階段
階段1:Bean元信息配置階段
這個階段主要是bean信息的定義階段。
Bean信息定義4種方式
- API的方式
- Xml文件方式
- properties文件的方式
- 注解的方式
API的方式
先來說這種方式,因為其他幾種方式最終都會采用這種方式來定義bean配置信息。
Spring容器啟動的過程中,會將Bean解析成Spring內(nèi)部的BeanDefinition結(jié)構(gòu)。 不管是是通過xml配置文件的 <Bean> 標(biāo)簽,還是通過注解配置的 @Bean ,還是 @Compontent 標(biāo)注的類,還是掃描得到的類,它最終都會被解析成一個BeanDefinition對象,最后我們的Bean工廠就會根據(jù)這份Bean的定義信息,對bean進行實例化、初始化等等操作。你可以把BeanDefinition丟給Bean工廠,然后Bean工廠就會根據(jù)這個信息幫你生產(chǎn)一個Bean實例,拿去使用。BeanDefinition里面里面包含了bean定義的各種信息,如:bean對應(yīng)的class、scope、lazy信息、dependOn信息、autowireCandidate(是否是候選對象)、primary(是否是主要的候選者)等信息。BeanDefinition是個接口,有幾個實現(xiàn)類,看一下類圖:

BeanDefinition接口:bean定義信息接口
表示bean定義信息的接口,里面定義了一些獲取bean定義配置信息的各種方法,來看一下源碼:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.beans.factory.config;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
/**
*設(shè)置此bean的父bean名稱(對應(yīng)xml中bean元素的parent屬性)
*/
void setParentName(@Nullable String var1);
@Nullable
String getParentName();
/**
* 指定此bean定義的bean類名(對應(yīng)xml中bean元素的class屬性)
*
*/
void setBeanClassName(@Nullable String beanClassName);
/**
* 返回此bean定義的當(dāng)前bean類名
* 注意,如果子定義重寫/繼承其父類的類名,則這不一定是運行時使用的實際類名。此外,這可能只
* 是調(diào)用工廠方法的類,或者在調(diào)用方法的工廠bean引用的情況下,它甚至可能是空的。因此,不要認為這是運
* 行時的最終bean類型,而只將其用于單個bean定義級別的解析目的。
* @return
*/
@Nullable
String getBeanClassName();
/**
* 設(shè)置此bean的生命周期,如:singleton、prototype(對應(yīng)xml中bean元素的scope屬性)
* @param scope 設(shè)置此bean的生命周期
*/
void setScope(@Nullable String scope);
/**
*
* @return 返回此bean的生命周期,如:singleton、prototype
*/
@Nullable
String getScope();
/**
* 設(shè)置是否應(yīng)延遲初始化此bean(對應(yīng)xml中bean元素的lazy屬性)
* @param lazyInit
*/
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
/**
* 設(shè)置此bean依賴于初始化的bean的名稱,bean工廠將保證dependsOn指定的bean會在當(dāng)前bean初
* 始化之前先初始化好
* @param depends
*/
void setDependsOn(@Nullable String... depends);
@Nullable
String[] getDependsOn();
/**
* 設(shè)置此bean是否作為其他bean自動注入時的候選者
* @param autowireCandidate
*/
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
/**
* 設(shè)置此bean是否為自動注入的主要候選者
* @param primary 是否為主要候選者
*/
void setPrimary(boolean primary);
boolean isPrimary();
/**
* 指定要使用的工廠bean(如果有)。這是要對其調(diào)用指定工廠方法的bean的名稱。
* @param factoryBeanName 工廠bean名稱
*/
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
/**
* 指定工廠方法(如果有)。此方法將使用構(gòu)造函數(shù)參數(shù)調(diào)用,如果未指定任何參數(shù),則不使用任何參
* 數(shù)調(diào)用。該方法將在指定的工廠bean(如果有的話)上調(diào)用,或者作為本地bean類上的靜態(tài)方法調(diào)用。
* @param factoryMethodName 工廠方法名稱
*/
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
/**
*
* @return 返回此bean的構(gòu)造函數(shù)參數(shù)值
*/
ConstructorArgumentValues getConstructorArgumentValues();
/**
*
* @return 是否有構(gòu)造器參數(shù)值設(shè)置信息(對應(yīng)xml中bean元素的<constructor-arg />子元素)
*/
default boolean hasConstructorArgumentValues() {
return !this.getConstructorArgumentValues().isEmpty();
}
/**
*
* @return 獲取bean定義是配置的屬性值設(shè)置信息
*/
MutablePropertyValues getPropertyValues();
/**
*
* @return 這個bean定義中是否有屬性設(shè)置信息(對應(yīng)xml中bean元素的<property />子元素)
*/
default boolean hasPropertyValues() {
return !this.getPropertyValues().isEmpty();
}
/**
*
* @param initMethodName 設(shè)置bean初始化方法名稱
*/
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
/**
*
* @param destroyMethodName 設(shè)置bean銷毀方法的名稱
*/
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
/**
*
* @param role 設(shè)置bean的role信息
*/
void setRole(int role);
int getRole();
/**
*
* @param description 設(shè)置bean描述信息
*/
void setDescription(@Nullable String description);
@Nullable
String getDescription();
/**
*
* @return 獲取bean類型解析器
*/
ResolvableType getResolvableType();
boolean isSingleton();
boolean isPrototype();
/**
*
* @return 對應(yīng)xml中bean元素的abstract屬性,用來指定是否是抽象的
*/
boolean isAbstract();
/**
*
* @return 返回此bean定義來自的資源的描述(以便在出現(xiàn)錯誤時顯示上下文)
*/
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
BeanDefinition接口上面還繼承了2個接口:
- org.springframework.core.AttributeAccessor
- org.springframework.beans.BeanMetadataElement
AttributeAccessor接口:屬性訪問接口
public interface AttributeAccessor {
/**
* 設(shè)置屬性->值
* @param name 屬性
* @param value 值
*/
void setAttribute(String name, @Nullable Object value);
/**
*
* @param name 獲取某個屬性對應(yīng)的值
* @return value
*/
@Nullable
Object getAttribute(String name);
/**
*
* @param name 移除某個屬性
* @return
*/
@Nullable
Object removeAttribute(String name);
/**
*
* @param name 是否包含某個屬性
* @return flag
*/
boolean hasAttribute(String name);
/**
*
* @return 返回所有的屬性名稱
*/
String[] attributeNames();
}
這個接口相當(dāng)于key->value數(shù)據(jù)結(jié)構(gòu)的一種操作,BeanDefinition繼承這個,內(nèi)部實際上是使用了
LinkedHashMap來實現(xiàn)這個接口中的所有方法,通常我們通過這些方法來保存BeanDefinition定義過程
中產(chǎn)生的一些附加信息。
BeanMetadataElement接口
public interface BeanMetadataElement {
@Nullable
default Object getSource() {
return null;
}
}
BeanDefinition繼承這個接口,getSource返回BeanDefinition定義的來源,比如我們通過xml定義
BeanDefinition的,此時getSource就表示定義bean的xml資源;若我們通過api的方式定義
BeanDefinition,我們可以將source設(shè)置為定義BeanDefinition時所在的類,出錯時,可以根據(jù)這個來
源方便排錯
RootBeanDefinition類:表示根bean定義信息
通常bean中沒有父bean的就使用這種表示
ChildBeanDefinition類:表示子bean定義信息
如果需要指定父bean的,可以使用ChildBeanDefinition來定義子bean的配置信息,里面有個parentName 屬性,用來指定父bean的名稱。
GenericBeanDefinition類:通用的bean定義信息
既可以表示沒有父bean的bean配置信息,也可以表示有父bean的子bean配置信息,這個類里面也有parentName屬性,用來指定父bean的名稱。
ConfigurationClassBeanDefinition類:表示通過配置類中@Bean方法定義bean信息
可以通過配置類中使用@Bean來標(biāo)注一些方法,通過這些方法來定義bean,這些方法配置的bean信息最后會轉(zhuǎn)換為ConfigurationClassBeanDefinition類型的對象
AnnotatedBeanDefinition接口:表示通過注解的方式定義的bean信息
里面有個方法
AnnotationMetadata getMetadata();
用來獲取定義這個bean的類上的所有注解信息。
BeanDefinitionBuilder:構(gòu)建BeanDefinition的工具類
spring中為了方便操作BeanDefinition,提供了一個類: BeanDefinitionBuilder ,內(nèi)部提供了很多靜態(tài)方法,通過這些方法可以非常方便的組裝BeanDefinition對象。
綜合案例
@Data
public class Pig {
private String name;
private Integer age;
private String description;
public Pig() {
}
public Pig(String name, Integer age) {
this.name = name;
this.age = age;
}
public Pig(String name, Integer age, String description) {
this.name = name;
this.age = age;
this.description = description;
}
}
再來一個依賴于上面的類
@Data
public class User {
private Pig pig;
private String name;
private List<Pig> pigList;
private Set<Pig> pigSet;
private Map<String, String> stringMap;
private Map<String, Pig> stringPigMap;
private List<String> strings;
private Set<String> stringSet;
}
先用xml方式定義user bean
<?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生命周期那一節(jié)的內(nèi)容 -->
<!--先定義兩頭豬 喬治和佩奇 -->
<bean id="pig" class="com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig">
<property name="name" value="jose" />
<property name="description" value="名字是喬治"/>
</bean>
<bean id="patch" class="com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig">
<property name="name" value="patch" />
<property name="description" value="名字是佩奇"/>
</bean>
<!-- end -->
<!-- 定義個user bean -->
<bean id="user" class="com.shiguiwu.springmybatis.spring.lifecycle.definition.User">
<!-- 設(shè)置自定義屬性 -->
<property name="pig" ref="patch" />
<!-- 設(shè)置 string 屬性 -->
<property name="name" value="小明" />
<!-- 設(shè)置 pig 對象的list集合 -->
<property name="pigList">
<list>
<ref bean="pig"/>
<ref bean="patch"/>
</list>
</property>
<!-- 設(shè)置 pig 對象的set集合 -->
<property name="pigSet">
<set>
<ref bean="pig"/>
<ref bean="patch"/>
</set>
</property>
<!-- 設(shè)置 string -> string對象的map集合 -->
<property name="stringMap">
<map>
<entry key="name" value="佩奇" />
<entry key="age" value="15.5"/>
</map>
</property>
<!-- 設(shè)置 string -> pig對象的map集合 -->
<property name="stringPigMap">
<map>
<entry key="pig" value-ref="pig" />
<entry key="patch" value-ref="patch"/>
</map>
</property>
<!-- 設(shè)置 string 對象的list集合 -->
<property name="strings" >
<list>
<value>小豬佩奇</value>
<value>喬治</value>
</list>
</property>
<!-- 設(shè)置 string 對象的set集合 -->
<property name="stringSet" >
<set>
<value>小豬佩奇1</value>
<value>喬治1</value>
</set>
</property>
</bean>
<!-- user bean end -->
</beans>
xml中的bean配置信息會被解析器解析為BeanDefinition對象,一會在第二階段詳解。
下面我們采用純api的方式實現(xiàn),如下
@1:調(diào)用addPropertyValue給Car中的name設(shè)置值
@2:創(chuàng)建了一個spring容器
@3:將carBeanDefinition這個bean配置信息注冊到spring容器中,bean的名稱為car
@4:從容器中獲取car這個bean,最后進行輸出
package com.shiguiwu.springmybatis.spring.lifecycle.definition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.ManagedSet;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @description:
* :通過api設(shè)置(Map、Set、List)屬性
* 下面我們來演示注入List、Map、Set,內(nèi)部元素為普通類型及其他bean元素。
* @author: stone
* @date: Created by 2021/3/17 15:36
* @version: 1.0.0
* @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.definition
*/
public class DefinitionApiTests {
public static void main(String[] args) {
BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(Pig.class.getName());
BeanDefinitionBuilder builder2 = BeanDefinitionBuilder.genericBeanDefinition(Pig.class);
BeanDefinition pig1 = builder1.addPropertyValue("name", "小豬佩奇")
.addPropertyValue("age", 12)
.getBeanDefinition();
BeanDefinition pig2 = builder2.addPropertyValue("name", "喬治111")
.addPropertyValue("age", 6)
.getBeanDefinition();
ManagedList<String> strings = new ManagedList<>();
strings.addAll(Arrays.asList("字符串1", "strings","list"));
ManagedSet<String> stringSet = new ManagedSet<>();
stringSet.add("set");
stringSet.add("注入set集合");
ManagedMap<String, String> stringMap = new ManagedMap<>();
stringMap.put("name", "小豬佩奇");
stringMap.put("age", "13");
List<RuntimeBeanReference> pigList = new ManagedList<>();
pigList.addAll(Arrays.asList(new RuntimeBeanReference("pig1"), new RuntimeBeanReference("pig2")));
Set<RuntimeBeanReference> pigSet = new ManagedSet<>();
pigSet.add(new RuntimeBeanReference("pig1"));
pigSet.add(new RuntimeBeanReference("pig2"));
Map<String, RuntimeBeanReference> stringPigMap = new ManagedMap<>();
stringPigMap.put("pig1", new RuntimeBeanReference("pig1"));
stringPigMap.put("pig2", new RuntimeBeanReference("pig2"));
BeanDefinition userDefinition = new GenericBeanDefinition();
userDefinition.setBeanClassName(User.class.getName());
userDefinition.getPropertyValues()
.add("pig", new RuntimeBeanReference("pig1"))
.add("name", "shiguiwu")
.add("pigList", pigList)
.add("pigSet", pigSet)
.add("stringMap", stringMap)
.add("stringPigMap", stringPigMap)
.add("strings", strings)
.add("stringSet", stringSet);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("pig1", pig1);
factory.registerBeanDefinition("pig2", pig2);
factory.registerBeanDefinition("user", userDefinition);
String[] beanDefinitionNames = factory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(factory.getBean(beanDefinitionName));
}
}
}
有幾點需要說一下:
RuntimeBeanReference:用來表示bean引用類型,類似于xml中的ref
ManagedList:屬性如果是List類型的,t需要用到這個類進行操作,這個類繼承了ArrayList
ManagedSet:屬性如果是Set類型的,t需要用到這個類進行操作,這個類繼承了LinkedHashSet
ManagedMap:屬性如果是Map類型的,t需要用到這個類進行操作,這個類繼承了
LinkedHashMap
上面也就是這幾個類結(jié)合的結(jié)果。
properties文件的方式
這種方式估計大家比較陌生,將bean定義信息放在properties文件中,然后通過解析器將配置信息解析為BeanDefinition對象。
properties內(nèi)容格式如下:
pig.(class)=com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig
pig.name=shiguiwu
pig.age=18
注解的方式
常見的2種:
- 類上標(biāo)注@Compontent注解來定義一個bean
- 配置類中使用@Bean注解來定義bean
小結(jié)
bean注冊者只識別BeanDefinition對象,不管什么方式最后都會將這些bean定義的信息轉(zhuǎn)換為BeanDefinition對象,然后注冊到spring容器中。
階段2:Bean元信息解析階段
Bean元信息的解析就是將各種方式定義的bean配置信息解析BeanDefinition對象。
Bean元信息的解析主要有3種方式
- xml文件定義bean的解析
- properties文件定義bean的解析
- 注解方式定義bean的解析
XML方式解析:XmlBeanDefinitionReader
spring中提供了一個類 XmlBeanDefinitionReader ,將xml中定義的bean解析為BeanDefinition對象。
xml文件為上一個階段的user.xml,這里我們直接解析他。
package com.shiguiwu.springmybatis.spring.lifecycle.parse;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
/**
* @description: 解析階段
* @author: stone
* @date: Created by 2021/3/21 18:41
* @version: 1.0.0
* @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.definition.parse
*/
public class XmlParseTests {
public static void main(String[] args) {
//定義一個spring容器,這個容器默認實現(xiàn)了BeanDefinitionRegistry,所以本身就是一個bean
//注冊器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//定義一個xml的BeanDefinition讀取器,需要傳遞一個BeanDefinitionRegistry(bean注冊器)對象
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//通過XmlBeanDefinitionReader加載bean xml文件,然后將解析產(chǎn)生的BeanDefinition注冊容器容器中
int count = reader.loadBeanDefinitions("spring/user.xml");
System.out.println("一共注冊多少bean ===>" + count);
for (String name : factory.getBeanDefinitionNames()) {
//根據(jù)名稱獲取定義
BeanDefinition beanDefinition = factory.getBeanDefinition(name);
//根據(jù)具體哪個bean定義
String className = beanDefinition.getClass().getName();
//獲取對象
Object bean = factory.getBean(name);
System.out.println(name +"===========================>");
System.out.println("beanDefinition = " + beanDefinition);
System.out.println("className = " + className);
System.out.println("bean = " + bean);
}
}
}
上面注釋比較詳細,這里就不解釋了。
注意一點:創(chuàng)建XmlBeanDefinitionReader的時候需要傳遞一個bean注冊器
(BeanDefinitionRegistry),解析過程中生成的BeanDefinition會丟到bean注冊器中。
00:01:26.660 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 3 bean definitions from class path resource [spring/user.xml]
一共注冊多少bean ===>3
00:01:26.676 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'pig'
pig===========================>
beanDefinition = Generic bean: class [com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig]; 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 [spring/user.xml]
className = org.springframework.beans.factory.support.GenericBeanDefinition
bean = Pig(name=jose, age=null, description=名字是喬治)
00:01:26.873 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'patch'
patch===========================>
beanDefinition = Generic bean: class [com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig]; 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 [spring/user.xml]
className = org.springframework.beans.factory.support.GenericBeanDefinition
bean = Pig(name=patch, age=null, description=名字是佩奇)
00:01:26.874 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
user===========================>
beanDefinition = Generic bean: class [com.shiguiwu.springmybatis.spring.lifecycle.definition.User]; 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 [spring/user.xml]
className = org.springframework.beans.factory.support.GenericBeanDefinition
bean = User(pig=Pig(name=patch, age=null, description=名字是佩奇), name=小明, pigList=[Pig(name=jose, age=null, description=名字是喬治), Pig(name=patch, age=null, description=名字是佩奇)], pigSet=[Pig(name=jose, age=null, description=名字是喬治), Pig(name=patch, age=null, description=名字是佩奇)], stringMap={name=佩奇, age=15.5}, stringPigMap={pig=Pig(name=jose, age=null, description=名字是喬治), patch=Pig(name=patch, age=null, description=名字是佩奇)}, strings=[小豬佩奇, 喬治], stringSet=[小豬佩奇1, 喬治1])
上面的輸出認真看一下,這幾個BeanDefinition都是 GenericBeanDefinition 這種類型的,也就是說xml中定義的bean被解析之后都是通過GenericBeanDefinition 這種類型表示的。
properties文件定義bean的解析:
主要是PropertiesBeanDefinitionReader類,這里主要是使用過程比較少,所以這里不做講解,感興趣的可以自行研究
注解方式:AnnotatedBeanDefinitionReader
注解的方式定義的bean,需要使用AnnotatedBeanDefinitionReader這個類來進行解析,方式也和上面2種方式類似,直接來看案例。
注冊的bean
package com.shiguiwu.springmybatis.spring.autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* @description:
* @author: stone
* @date: Created by 2021/3/15 14:39
* @version: 1.0.0
* @pakeage: com.shiguiwu.springmybatis.spring.autowired
*/
@Service
public class B implements C {
}
測試代碼如下:
package com.shiguiwu.springmybatis.spring.lifecycle.parse;
import com.shiguiwu.springmybatis.spring.autowired.B;
import com.shiguiwu.springmybatis.spring.autowired.resource.Rb;
import com.shiguiwu.springmybatis.spring.autowired.resource.Rc;
import com.shiguiwu.springmybatis.spring.lazy.A;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
/**
* @description: 2,注解解析類
* @author: stone
* @date: Created by 2021/3/23 10:16
* @version: 1.0.0
* @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.parse
*/
public class AnnotatedParseTests {
public static void main(String[] args) {
//1定義一個容器,一個注冊器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//2定義一個注解讀取器
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(factory);
//3注冊到注解解析器中
reader.register(B.class);
System.out.println(factory.getBean("b"));
System.out.println(factory.getBeanDefinition("b").getClass().getName());
System.out.println("========================");
factory.getBeansOfType(BeanPostProcessor.class).values().forEach(factory::addBeanPostProcessor); // @1
// String[] beanDefinitionNames = factory.getBeanDefinitionNames();
// for (String name : beanDefinitionNames) {
// System.out.println(factory.getBean(name));
// System.out.println("========================");
// }
}
}
階段3:Spring Bean注冊階段
bean注冊階段需要用到一個非常重要的接口:BeanDefinitionRegistry
Bean注冊接口:BeanDefinitionRegistry
這個接口中定義了注冊bean常用到的一些方法,源碼如下:
public interface BeanDefinitionRegistry extends AliasRegistry {
/**
*
* 注冊一個新的bean定義
* @param beanName bean的名稱
* @param beanDefinition bean定義信息
* @throws BeanDefinitionStoreException
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
/**
* 通過bean名稱移除已注冊的bean
* @param beanName bean的名稱
* @throws NoSuchBeanDefinitionException
*/
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* 通過名稱獲取bean的定義信息
* @param beanName bean的名稱
* @return bean定義信息
* @throws NoSuchBeanDefinitionException
*/
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* 查看beanName是否注冊過
* @param beanName bean的名稱
* @return 是否注冊過
*/
boolean containsBeanDefinition(String beanName);
/**
* 獲取已經(jīng)定義(注冊)的bean名稱列表
* @return bean名稱列表
*/
String[] getBeanDefinitionNames();
/**
*
* @return 返回注冊器中已注冊的bean數(shù)量
*/
int getBeanDefinitionCount();
/**
* 確定給定的bean名稱或者別名是否已在此注冊表中使用
* beanName:可以是bean名稱或者bean的別名
* @param beanName bean名稱
* @return 是否已經(jīng)注冊過
*/
boolean isBeanNameInUse(String beanName);
}
別名注冊接口:AliasRegistry
BeanDefinitionRegistry 接口繼承了 AliasRegistry 接口,這個接口中定義了操作bean別名的一些方法,看一下其源碼:
public interface AliasRegistry {
/**
* 給name指定別名alias
* @param name beanName
* @param alias alias
*/
void registerAlias(String name, String alias);
/**
*
* @param alias 從此注冊表中刪除指定的別名
*/
void removeAlias(String alias);
/**
*
* @param name 判斷name是否作為別名已經(jīng)被使用了
* @return 返回
*/
boolean isAlias(String name);
/**
*
* @param name bean的名稱
* @return 返回name對應(yīng)的所有別名
*/
String[] getAliases(String name);
}
BeanDefinitionRegistry唯一實現(xiàn):DefaultListableBeanFactory
spring中BeanDefinitionRegistry接口有一個唯一的實現(xiàn)類:
org.springframework.beans.factory.support.DefaultListableBeanFactory
大家可能看到有很多類也實現(xiàn)了 BeanDefinitionRegistry 接口,比如我們經(jīng)常用到的
AnnotationConfigApplicationContext ,但實際上其內(nèi)部是轉(zhuǎn)發(fā)給了
DefaultListableBeanFactory 進行處理的,所以真正實現(xiàn)這個接口的類是
DefaultListableBeanFactory 。
大家再回頭看一下開頭的幾個案例,都使用的是 DefaultListableBeanFactory 作為bean注冊器,此時你們應(yīng)該可以理解為什么了。
下面我們來個案例演示一下上面常用的一些方法。
package com.shiguiwu.springmybatis.spring.lifecycle.register;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import java.util.Arrays;
/**
* @description: 3,注冊階段。。。
* @author: stone
* @date: Created by 2021/3/23 12:45
* @version: 1.0.0
* @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.register
*/
public class RegisterTests {
public static void main(String[] args) {
//1 定義個注冊器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//定義一個bean定義信息
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(String.class);
definition.getConstructorArgumentValues().addIndexedArgumentValue(0, "shiguiwu");
//注冊一個組件
factory.registerBeanDefinition("name", definition);
//是否包括某組件
System.out.println(factory.containsBean("name"));
//獲取定義信息
System.out.println(factory.getBeanDefinition("name"));
//是否注冊過bean定義
System.out.println(factory.containsBeanDefinition("name"));
//獲取所有注冊信息
System.out.println(Arrays.asList(factory.getBeanDefinitionNames()));
//獲取bean定義的數(shù)量
System.out.println(factory.getBeanDefinitionCount());
//是否使用過名稱
System.out.println(factory.isBeanNameInUse("name"));
System.out.println("別名相關(guān)操作。。。。。。。。。。。。。。。。。");
//注冊兩個別名
factory.registerAlias("name","alias-name-1");
factory.registerAlias("name", "alias-name-2");
//判斷別名是否已經(jīng)使用
System.out.println(factory.isAlias("alias-name-2"));
//獲取所以別名
System.out.println(Arrays.asList(factory.getAliases("name")));
System.out.println(factory.getBean("name"));
}
}
運行輸出如下:
Connected to the target VM, address: '127.0.0.1:55842', transport: 'socket'
true
Generic bean: class [java.lang.String]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
true
[name]
1
true
別名相關(guān)操作。。。。。。。。。。。。。。。。。
true
[alias-name-2, alias-name-1]
17:34:32.427 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'name'
shiguiwu
自此,Spring bean的生命周期前篇結(jié)束,由于篇幅較多,我把它分開前,中,后篇。