Spring原始碼-getBean獲取bean例項
例項化Bean
單例bean,並且lazy-init為false(預設是false),則 ApplicationContext在重新整理的時候就例項化該Bean,並且將例項化的Bean放到快取中,下次再使用該Bean的時候, 直接從這個快取中獲取;如果單例bean是懶載入的,即lazy-init為true,則在第一次getBean獲取該Bean的時候進行例項化,並放入快取;scope是prototype的多例bean,每次使用獲取Bean的時候都會進行例項化
<bean id="" class=" " scope="作用域"/>
1. singleton: 單例 ,在Spring IoC容器中僅存在一個Bean例項 (預設的scope)
2. prototype: 多例 ,每次從容器中呼叫Bean時,都返回一個新的例項,即每次呼叫getBean()
3. request: 用於web開發,將Bean放入request範圍 , 在同一個request 獲得同一個Bean
4. session: 用於web開發,將Bean 放入Session範圍,在同一個Session 獲得同一個Bean
spring容器預設載入bean為非延遲載入,在容器重新整理階段就會例項化bean物件,設定為延遲載入則當類首次被載入時才會初始化例項,所有bean的例項化都是通過getBean去實現
<!--當前xml中所有的bean-->
<beans default-lazy-init="default | false | true">
<!--指定的bean-->
<bean lazy-init="default | false | true">
使用註解方式
@Lazy
public class Bean {}
總結所有bean的生命週期:單例且非延遲載入的bean跟隨容器重新整理完成例項初始化,之後訪問例項從快取中獲取;單例延遲載入的bean在首次訪問時通過getBean完成例項化,之後訪問從快取中獲取;
Bean例項化的方式
無引數構造器例項化
<bean id="super" name="a1,a2,a3" class="cn.mywork.spring.Super" lazy-init="true"/>
靜態工廠方法例項化
//factory-method找到工廠類的靜態方法
<bean id="student" class="cn.mywork.spring.StaticFactory" factory-method="getStu"/>
//配置靜態工廠類
public class StaticFactory {
//通過配置檔案找到靜態方法,返回物件為建立的bean
public static Student getStu(){
return new Student();
}
}
ApplicationContext context;
Student student = context.getBean("student", Student.class);
例項工廠
//先將工廠bean交給容器管理
<bean id="instanceFactory" name="fc" class="cn.mywork.wms.spring.InstanceFactory"/>
//factory-bean只能是初始化好的bean物件,通過bean工廠物件,獲取例項方法初始化bean
<bean id="student" factory-bean="fc" factory-method="getStu"/>
實現FactoryBean介面,通過getObject方法返回目標例項
//實現getObject方法
public class InstanceFactory implements FactoryBean<Student>{
@Override
public Student getObject() throws Exception {
return new Student();
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
<bean id="student" class="cn.mywork.spring.InstanceFactory"/>
註解的方式
//註解對應的配置解析
<bean id="super" class="cn.mywork.wms.spring.Super" init-method="init" destroy-method="destory" scope="prototype">
<!--注入的屬性-->
<property name="sub" ref="sub"/>
</bean>
<bean id="sub" class="cn.mywork.wms.spring.Sub"/>
//預設的為簡化的類名,Xml裡也同於bean標籤的id值
@Component("super")
//作用域:非單例
@Scope("prototype")
public class Super {
private String name;
//注入Sub初始化的例項
@Autowired
private Sub sub;
//初始化的方法,init-method="init"
@PostConstruct
public void init(){
}
//銷燬的方法,destroy-method="destory"
@PreDestroy
public void destory(){
}
}
自定義BeanFactory工廠
public class BeanFactoryDemo {
//key為id,value為全限定名
private static Map<String,String> beanMap = new HashMap<>();
//bean快取,延遲載入bean時,genBean之後將bean放入快取
private static Map<String,Object> cacheMap = new HashMap<>();
//解析xml配置檔案
static {
try {
//getClassLoader().getResourceAsStream是載入resources資源路徑下的配置檔案
InputStream resource = BeanFactoryDemo.class.getClassLoader().getResourceAsStream("spring.xml");
initBeanMap(resource);
}catch (Exception e){}
}
private static void initBeanMap(InputStream resource) throws Exception {
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
saxParser.parse(resource,new DefaultHandler(){
//解析後的標籤名
private String tagName;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
this.tagName = qName;
//獲取標籤內容
if ("bean".equals(tagName)){
//獲取id的值
String id = attributes.getValue("id");
//獲取bean的全限定名
String beanClassName = attributes.getValue("class");
beanMap.put(id,beanClassName);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
tagName = null;
}
});
}
//獲取bean例項的方法,延遲載入方式
public static <T> T getBean(String id,Class<T> beanClass) throws Exception{
//只有map中存在的key值才會繼續處理
if (beanMap.containsKey(id)){
//再判斷快取中是否有該bean
if (cacheMap.containsKey(id)){
return (T) cacheMap.get(id);
}
String beanClassName = beanMap.get(id);
//載入全限定名,通過反射機制建立bean
Object instance = Class.forName(beanClassName).newInstance();
//判斷是否為beanClass型別的例項
if (beanClass.isInstance(instance)){
cacheMap.put(id,instance);
return (T) instance;
}
}
return null;
}
}
Student student = BeanFactoryDemo.getBean("student", Student.class);
getBean
refresh執行到finishBeanFactoryInitialization時才開始例項化非延遲載入的bean,主要看其中的preInstantiateSingletons方法
public void preInstantiateSingletons() throws BeansException {
//所有的需要例項化的beanName都在beanDefinitionNames,包括 Aspectj的, 通過註解標識的
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
//合併父類BeanDefinition
//MergedBeanDefinition合併bean定義,XML 配置來註冊 bean,會被封裝成GenericBeanDefinition;使用註解的方式來註冊 bean,會被封裝成 ScannedGenericBeanDefinition,最終統一轉換成 RootBeanDefinition處理
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//非抽象,單例,非懶載入三個條件
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//是 FactoryBean 型別的物件則加上&
//判斷是factoryBean還是普通bean,實現FactoryBean介面的getObject()方法可以定義建立例項物件,比如很多中介軟體的就是通過這種方式實現
if (isFactoryBean(beanName)) {
bean = getBean(FACTORY_BEAN_PREFIX + beanName);
...
}
else {
// 進入到doGetBean執行例項化bean
bean = getBean(beanName);
}
}
}
}
容器初始化完成還是在初始化之後動態獲取bean都會訪問beanFacroty.getBean()方法,進入這個方法發現有很多分支去獲取bean,如果不是首次獲取bean則直接getSingleton()先從快取中獲取
protected <T> T doGetBean(String name, Class<T> requiredType,Object[] args, boolean typeCheckOnly) throws BeansException {
//去掉FactoryBean的字首“&”,解析別名返回namespace的beanName
String beanName = this.transformedBeanName(name);
//獲取快取中的bean,不涉及建立新的bean例項和解決迴圈依賴
Object sharedInstance = this.getSingleton(beanName);
Object bean;
//快取中如果能獲取到
if (sharedInstance != null && args == null) {
//普通bean直接返回例項,factoryBean繼續處理
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
//和singletonsCurrentlyInCreation類似存放正在建立的Prototype例項
//迴圈依賴校驗:當前原型例項池中有正在建立的物件了,說明這個物件是個原型物件,並且當前執行緒中這個物件已經處於建立中了,會造成迴圈依賴
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = this.getParentBeanFactory();
//當前BeanFactory中的beanDefinitionMap找不到當前Bean,則從parentBeanFactory獲取
if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
//解析別名和去掉FactoryBean的字首
String nameToLookup = this.originalBeanName(name);
//使用父類的doGetBean方法例項化bean
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
...
}
//型別檢測預設為false,將beanName新增到alreadyCreated快取
if (!typeCheckOnly) {
this.markBeanAsCreated(beanName);
}
//RootBeanDefinition可以理解為一個沒有parent的獨立BeanDefinition
//Map<String, RootBeanDefinition> mergedBeanDefinitions
//如果mergedBeanDefinitions沒有父類定義就是BeanDefinition本身
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
//檢查是抽象類則拋異常
this.checkMergedBeanDefinition(mbd, beanName, args);
//獲取所有當前bean的依賴,需要在依賴建立之後才能進行例項建立
//@DependsOn這個熟悉的註解:需要依賴另一個bean的例項建立
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 檢查是否依賴於beanName,即存在迴圈依賴
if (isDependent(beanName, dep)) {
throw new BeanCreationException();
}
//將dep和beanName的依賴關係註冊到dependentBeanMap中
registerDependentBean(dep, beanName);
//先例項化依賴的Bean
getBean(dep);
}
//例項化不同的scope域的Bean
if (mbd.isSingleton()) {
//過載方法
//getSingleton(String beanName, ObjectFactory<?> singletonFactory)
sharedInstance = this.getSingleton(beanName, () -> {
//singletonFactory.getObject()方法最終執行的是createBean()方法
try {
return this.createBean(beanName, mbd, args);
} catch (BeansException var5) {
this.destroySingleton(beanName);
throw var5;
}
});
//跟上面一樣不是factoryBean則返回普通的例項物件
bean = this.getObjectForBeanInstance(sharedInstance,name,beanName, mbd);
} else if (mbd.isPrototype()) {
//scope為prototype的bean建立
var11 = null;
Object prototypeInstance;
try {
//新增到快取prototypesCurrentlyInCreation中
this.beforePrototypeCreation(beanName);
//建立例項
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
//移除prototypesCurrentlyInCreation中的快取
this.afterPrototypeCreation(beanName);
}
//普通Bean直接返回
bean=this.getObjectForBeanInstance(prototypeInstance,name,beanName, mbd);
} else {
//其他scope的bean建立
String scopeName = mbd.getScope();
Scope scope = (Scope)this.scopes.get(scopeName);
//實現的也是ObjectFactory
Object scopedInstance = scope.get(beanName, () -> {
//通過getObject方法呼叫,和prototype建立bean例項一致
this.beforePrototypeCreation(beanName);
Object var4;
try {
var4 = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
return var4;
});
bean=this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
}
}
}...
factoryBean
回到doGetBean()方法,如果獲取到快取則繼續進入getObjectForBeanInstance()交給factoryBean處理
//bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//表示name以“&”為字首但不是factoryBean則拋異常
if (BeanFactoryUtils.isFactoryDereference(name)) {
...
//不是factoryBean則直接返回
} else if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
} else {
//快取中拿到的是一個factoryBean
Object object = null;
if (mbd != null) {
//標註這個beanDefinition為factoryBean
mbd.isFactoryBean = true;
} else {
//入參mbd為null,所以需要從factoryBeanObjectCache快取拿到例項
//Map<String, Object> factoryBeanObjectCache 用於快取factoryBean
object = this.getCachedObjectForFactoryBean(beanName);
}
//快取中也沒有
if (object == null) {
FactoryBean<?> factory = (FactoryBean)beanInstance;
//從beanDefinitionMap註冊的快取中找到beanDefinition
if (mbd == null && this.containsBeanDefinition(beanName)) {
//獲取合併(父容器)後的RootBeanDefinition
mbd = this.getMergedLocalBeanDefinition(beanName);
}
//mbd是否是合成的,一般為false
boolean synthetic = mbd != null && mbd.isSynthetic();
//使用factory去例項化bean
object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
}
factoryBean是一個特殊的bean,實現FactoryBean介面,factoryBean在被初始化時會呼叫其getObject()方法建立應用的bean
//注入一個factoryBean
@Component
public class MyFactoryBean implements FactoryBean<HahaBean> {
@Override
public HahaBean getObject() throws Exception {
//比如通過getBean(MyFactoryBean.class)則會返回hahaBean例項
return new HahaBean();
}
@Override
public Class<?> getObjectType() {
return HahaBean.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
//getBean()會通過doGetBean方法獲取bean例項
public class SingleManApp {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(StartUp.class);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
HahaBean myFactoryBean = (HahaBean) beanFactory.getBean("myFactoryBean");
myFactoryBean.test();
}
}
@SpringBootApplication
public class StartUp {
}
//最終返回的例項
public class HahaBean {
public void test(){
System.out.println("hahabean");
}
}
dependsOn
Spring提供比如@DependsOn/depends-on用於控制bean初始化順序,為了便於理解就不以’依賴’表示bean的關係,而是從邏輯上出發,A depends-on B,A的例項化需要B,則B優先於A進行例項化
// 檢查是否存在類似於A depondson B,而B depends-on A 的情況
if (isDependent(beanName, dep)) {
throw new BeanCreationException();
}
//將dep和beanName的depends-on關係註冊到dependentBeanMap中
registerDependentBean(dep, beanName);
//先例項化當前bean depends-on的Bean
getBean(dep);
首先判斷是否存在迴圈depends-on,保證不存在死迴圈問題,比如A dep B,B dep C,C dep A
//dependentBeanMap存放的是depends-on當前bean的例項集合
Map<String, Set<String>> dependentBeanMap;
//dependenciesForBeanMap存放當前優先於當前bean初始化的
Map<String, Set<String>> dependenciesForBeanMap;
//alreadySeen預設為null表示還沒有檢查過
private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
//表示已經檢查過了
if (alreadySeen != null && ((Set)alreadySeen).contains(beanName)) {
return false;
} else {
//如果是別名則解析別名
String canonicalName = this.canonicalName(beanName);
//dependentBeanMap這個集合存放的bean應該是在當前bean例項化之後才進行初始化
Set<String> dependentBeans = (Set)this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
return false;
//但是dependentBeanName應該優先例項化的bean卻在dependentBeans中這就會造成死迴圈
} else if (dependentBeans.contains(dependentBeanName)) {
return true;
//這一步就是徹底找到 A - B,B - C,C - D,D - A 這種隔層 depends-on
} else {
Iterator var6 = dependentBeans.iterator();
String transitiveDependency;
do {
if (!var6.hasNext()) {
return false;
}
transitiveDependency = (String)var6.next();
if (alreadySeen == null) {
alreadySeen = new HashSet();
}
((Set)alreadySeen).add(beanName);
} while(!this.isDependent(transitiveDependency, dependentBeanName, (Set)alreadySeen));
return true;
}
}
}
registerDependentBean:在例項化優先的bean例項之前還需要將相互順序關係進行維護
//注意入參registerDependentBean(dep, beanName),實際deponds-on的bean位置換成了beanName
//為了方便理解還是按照依賴順序將首先例項化的稱為A(beanName),dependentBeanName稱為B
public void registerDependentBean(String beanName, String dependentBeanName) {
String canonicalName = this.canonicalName(beanName);
// depends-on Bean的對映集合
Map var4 = this.dependentBeanMap;
//depends-on A的集合(順序在A之後)
Set dependenciesForBean;
synchronized(this.dependentBeanMap) {
//java8新方法computeIfAbsent方法用來計算給定key,返回value對映值。如果,key並沒有對映到一個值,或者對映到null,那麼,就用這個value值放到這個hashmap中
//獲取deponds-on A的集合
dependenciesForBean = (Set)this.dependentBeanMap
.computeIfAbsent(canonicalName, (k) -> {
return new LinkedHashSet(8);
});
//將B維護到deponds-on A的集合
if (!dependenciesForBean.add(dependentBeanName)) {
return;
}
}
//Bean depends-on的集合對映
var4 = this.dependenciesForBeanMap;
synchronized(this.dependenciesForBeanMap) {
//獲取B depends-on的集合,並將A維護進去
dependenciesForBean = (Set)this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, (k) -> {
return new LinkedHashSet(8);
});
dependenciesForBean.add(canonicalName);
}
}
getSingleton
單例bean的例項化流程
1.解析別名(如果有)獲取bean的名字
2.如果scope為sigleton則從快取中查詢是否有這個bean,否則跳過
3.首次獲取bean通過getSingleton建立bean的例項
4.標記這個bean已經被建立了(允許迴圈依賴則Spring通過三級快取解決,提前將bean曝光)
5.遞迴獲取依賴的bean並完成例項化
6.當前bean進行屬性注入
在非懶載入bean隨容器啟動時,載單例bean首次訪問時進行例項化,通過呼叫getBean訪問getSingleton
if (mbd.isSingleton()) {
//入參ObjectFactory通過getObject獲取最終的例項
sharedInstance = this.getSingleton(beanName, () -> {
try {
//實現ObjectFactory介面的getObject()方法
return this.createBean(beanName, mbd, args);
} catch (BeansException var5) {
this.destroySingleton(beanName);
throw var5;
}
});
//判斷建立的bean是否為factoryBean,如果是則通過factoryBean去建立例項
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
Spring三級快取解決迴圈依賴
只有單例bean且在earlySingletonExposure為true時(預設為true)才允許迴圈依賴的情況下才有二三級快取
Spring 能解決的迴圈依賴有:通過 setter 注入的迴圈依賴、通過屬性注入的迴圈依賴,當構造器出現迴圈依賴則無法解決,所以需要先用建構函式建立一個 “不完整” 的 bean 例項
//singletonObjects 一級快取:例項化儲存的單例 bean 物件
private final Map<String, Object> singletonObjects;
//earlySingletonObjects 二級快取:還未進行屬性填充
private final Map<String, Object> earlySingletonObjects;
//singletonFactories 三級快取:存放BeanName與bean工廠
private final Map<String, ObjectFactory<?>> singletonFactories;
//在Bean開始例項化時將bean存放,建立完成時會將其移出
private final Set<String> singletonsCurrentlyInCreation;
//Bean被建立完成後新增
private final Set<String> alreadyCreated;
//已經註冊的單例bean,三級快取中任意添加了都會同步新增到這裡
private final Set<String> registeredSingletons
解決迴圈依賴的原理
1.滿足條件下,比如有兩個bean A和B迴圈依賴,在A例項化getBean時會暴露到三級快取中,進行屬性注入populate時發現依賴B,則先去例項化B;
2.B例項化過程中也會暴露到三級快取中,在注入屬性時又發現依賴於A;
3.此時再次訪問getBean(A),由於A已經存在三級快取,所以在獲取A快取時通過三級快取獲取A的原始bean新增到二級快取中,並返回快取的A例項,A注入到B;
4.B完成屬性注入之後放入一級快取中,然後A完成了屬性的注入並獲取了二級快取,清除二級快取放入一級快取
singleton例項由實現ObjectFactory介面getObject方法返回createBean()實現
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Map var3 = this.singletonObjects;
synchronized(this.singletonObjects) {
//還是先從快取中拿
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//當前bean是正在destruction狀態,預設false
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException();
}
//建立例項前的驗證
//先校驗beanName不是要在建立檢查排除掉的(inCreationCheckExclusions快取)
//且新增到正在建立bean的快取singletonsCurrentlyInCreation中,新增失敗就表示已存在
this.beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
//執行creatBean()方法,由入參singletonFactory中getObject方法返回
//如果執行迴圈依賴則返回的是二級快取
singletonObject = singletonFactory.getObject();
newSingleton = true;
} finally {
//從singletonsCurrentlyInCreation移除beanName
this.afterSingletonCreation(beanName);
}
if (newSingleton) {
/**建立新的Bean成功新增到一級快取中,並移除二三級快取
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName); //已註冊的bean
**/
this.addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
當earlySingletonExposure為true表示允許迴圈依賴從而新增一個三級快取ObjectFactory
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) {
RootBeanDefinition mbdToUse = mbd;
//...
//當存在InstantiationAwareBeanPostProcessor時執行處理器的applyBeanPostProcessorsBeforeInstantiation和applyBeanPostProcessorsAfterInitialization
Object beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
if (beanInstance != null) {
return beanInstance;
}
//返回完整的Bean例項
beanInstance = this.doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
//bean包裝類
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//如果是factoryBean則清除快取
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//建立Bean例項,進行包裝,實現構造器依賴注入
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
//獲取原始物件和其型別
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//MergedBeanDefinitionPostProcessor,處理RootBeanDefinition
//@Autowired通過子類AutowiredAnnotationBeanPostProcessor實現將標有註解的欄位和方法放入快取
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
//滿足單例,允許迴圈依賴,正在例項建立中三個條件
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
//解決迴圈依賴,新增三級快取singletonFactory,移出二級快取
//this.singletonFactories.put(beanName, singletonFactory);
//this.earlySingletonObjects.remove(beanName);
//this.registeredSingletons.add(beanName);
this.addSingletonFactory(beanName, () -> {
//實現SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法
//可以實現AOP的邏輯,如果沒有增強處理則三級快取就是原始的bean
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
Object exposedObject = bean;
//完成屬性和方法的依賴注入
this.populateBean(beanName, mbd, instanceWrapper);
//bean增強,@PostConstruct>InitializingBean>init()
//依次:處理aware介面,執行BeanPostProcessors中postProcessBeforeInitialization方法,呼叫初始化方法init-Methods,執行BeanPostProcessor的postProcessAfterInitialization方法
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
//解決迴圈依賴
if (earlySingletonExposure) {
//呼叫過載的方法,在獲取快取時也訪問的是這個方法,用於獲取二級快取
Object earlySingletonReference = this.getSingleton(beanName, false);
if (earlySingletonReference != null) {
//initializeBean沒有處理bean則將二級快取進行進行暴露
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
//initializeBean處理之後會產生一個代理物件且有被依賴的bean
} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
//將這些依賴exposedObject的bean陣列移除,因為Bean已經不是原來的bean了
String[] dependentBeans = this.getDependentBeans(beanName);
...
}
}
}
//註冊用於銷燬的bean,執行銷燬操作的有三種:自定義destroy方法、DisposableBean介面、DestructionAwareBeanPostProcessor
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
通過三級快取singletonObject獲取二級快取的過載的方法
---DefaultSingletonBeanRegistry
//allowEarlyReference表示是否允許從singletonFactories中通過getObject拿到物件,預設true
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//從一級快取中獲取
Object singletonObject = this.singletonObjects.get(beanName);
//isSingletonCurrentlyInCreation表示正在進行建立中,且從一級快取中未獲取到例項
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
Map var4 = this.singletonObjects;
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
//二級快取也不存在且允許迴圈依賴
if (singletonObject == null && allowEarlyReference) {
//獲取ObjectFactory,從例項工廠獲取例項
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
//允許迴圈依賴則會存在一個三級快取
if (singletonFactory != null) {
//通過這個三級快取的getObject()方法實現,如果沒有增強處理則是原始bean
singletonObject = singletonFactory.getObject();
//獲取到了則新增到二級快取中,並移除三級快取的物件
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
//這個getSingleton方法的過載就是從快取獲取bean例項,沒有則去建立新的例項
return singletonObject;
}
prototypes例項的建立
多例的快取放在ThreadLocal快取中,每個執行緒獲取的都是通過getBean例項化的新物件,將 beanName 新增到 prototypesCurrentlyInCreation 快取
private final ThreadLocal<Object> prototypesCurrentlyInCreation;
try {
//例項化之前先新增快取到當前執行緒中
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
//清除當前執行緒的快取
this.afterPrototypeCreation(beanName);
}
protected void beforePrototypeCreation(String beanName) {
//prototype的bean的beanName集合
Object curVal = this.prototypesCurrentlyInCreation.get();
// 將ThreadLocal設定成當前的beanName
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
// 如果快取不為空且為String型別,則表示只有一個beanName
else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet<String>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
}
// 如果存在多個beanName,將當前的beanName新增到Set
else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}
initializeBean的順序
完成屬性注入之後執行initializeBean,先說結論,先通過處理器執行@PostConstruct註解標註的方法,通過invokeInitMethods先執行InitializingBean介面的afterPropertiesSet()方法,最後才執行init-method方法
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//如果bean是aware實現類,則將beanName,beanFactory分別新增到BeanNameAware和BeanFactoryAware
this.invokeAwareMethods(beanName, bean);
Object wrappedBean;
//執行BeanPostProcessor的applyBeanPostProcessorsBeforeInitialization方法
//InitDestroyAnnotationBeanPostProcessor在這一步會執行@PostConstruct標註的方法
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// 處理InitializingBean和init-method
this.invokeInitMethods(beanName, wrappedBean, mbd);
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
執行InitDestroyAnnotationBeanPostProcessor處理器時找到並invoke被標註的方法
//在方法上通過註解@PostConstruct標註為初始化的方法
//標註為初始化的方法
@PostConstruct
public void init(){
System.out.println("init");
}
//銷燬的方法
@PreDestroy
public void destroy(){
System.out.println("destroy");
}
進入invokeInitMethods方法,首先會判斷bean是否實現了InitializingBean,如果是則執行afterPropertiesSet()方法.下一步從initMethods獲取init的方法,init-method是在xml解析時封裝在beanDefinition的initMethods
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
//InitializingBean實現類完成初始化方法
boolean isInitializingBean = bean instanceof InitializingBean;
((InitializingBean)bean).afterPropertiesSet();
//init-method指定的初始化方法
String initMethodName = mbd.getInitMethodName();
this.invokeCustomInitMethod(beanName, bean, mbd);
}
//實現InitializingBean介面的afterPropertiesSet方法
@Service
public class TxService implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean");
}
}
也可以通過@Bean指定init-method方法:
@Bean(initMethod = "init")
public InitService getInit(){
return new InitService();
}
public class InitService {
public void init(){
System.out.println("init");
}
}
屬性注入
DI目的是在初始化物件時,根據物件中的屬性依賴, 動態將容器中bean按需注入進去,無需手動維護依賴關係,比如兩個交給spring管理的bean,其中A依賴B,這時就需要先例項化B並注入到A中,實現屬性填充;
構造器注入
首先要回到doCreateBean方法中有一個createBeanInstance就是用於構造器注入
//構造器例項化
Object instance = constructor.newInstance();
根據beanName、mbd建立Bean例項,args是bean的建構函式引數,根據args選擇不同的建構函式
//進入doCreateBean方法,通過createBeanInstance建立beanDefinition對應的包裝例項
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
//ClassUtils.forName(className, dynamicLoader);
Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
//理解為提供一個靜態方法回撥建立例項,比如static MyBean createMyBean(){new MyBean();}
//beanDefinition.setInstanceSupplier(SupplierBean::createUser);
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return this.obtainFromSupplier(instanceSupplier, beanName);
} else if (mbd.getFactoryMethodName() != null) {
//使用工廠方法去建立例項
return this.instantiateUsingFactoryMethod(beanName, mbd, args);
} else {
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
//不為null,則表示快取有被解析的構造器
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
//判斷是否需要自動注入,預設是false
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
//args為null
if (resolved) {
//true建構函式自動注入,false選擇使用預設的建構函式
return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);
}
//SmartInstantiationAwareBeanPostProcessor選擇候選的建構函式
//@Autowired就是通過子類AutowiredAnnotationBeanPostProcessor實現注入
Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
//ctors不為空 || mbd的注入方式為AUTOWIRE_CONSTRUCTOR || mdb定義了建構函式的引數值 || args不為空,執行建構函式自動注入
if (ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)) {
//理解為public的構造器
ctors = mbd.getPreferredConstructors();
//autowireConstructor自動注入的選舉流程:優先public方法,根據入參的args引數個數(做解析返回最終的引數個數)找到符合引數大於或等於的候選構造器,instantiateBean沒有args引數當然預設使用無參構造器;和autowireConstructor一樣最後通過BeanUtils.instantiateClass(ctor, args)構建原始例項;
return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);
} else {
return this.autowireConstructor(beanName, mbd, ctors, args);
}
}
}
determineConstructorsFromBeanPostProcessors方法用於執行determineCandidateConstructors方法,主要的實現類有AutowiredAnnotationBeanPostProcessor,看處理器名字就知道是處理@Autowired,主要作用也是用於給定 bean 的候選建構函式,因為原始碼很長,包括處理器是如何載入到容器中,暫時留個坑,大致理解一下處理器determineCandidateConstructors方法的作用
1.處理@Lookup註解,如果一個單例BeanA依賴多例的BeanB,因為BeanA是單例,在初始化一次之後就放入快取,所以BeanB也是beanA首次初始化依賴的beanB時所建立的例項;使用@Lookup註解標註在構造器方法或者普通方法用於生成子類去重寫這個方法,每次呼叫時會去調子類則形成依賴的更新;將@Lookup方法新增到lookupMethodsChecked快取
2.從candidateConstructorsCache.get(beanClass)快取中獲取已存在解析的構造器,否則繼續通過放射方法getDeclaredConstructors獲取類的所有構造器放入rawCandidates快取
3.遍歷所有構造器並進行分類快取:
// 存放@Autowire註解的建構函式
List<Constructor<?>> candidates = new ArrayList<Constructor<?>>(rawCandidates.length);
// 存放@Autowire註解,並且require=true的建構函式
Constructor<?> requiredConstructor = null;
// 存放預設的建構函式
Constructor<?> defaultConstructor = null;
4.如果不存在required=true則將預設構造器放入candidates,然後將集合轉為Constructor<?>[]陣列,如果只有構造器且非預設則單獨放入候選構造器陣列,其他情況返回空new Constructor<?>[0]陣列,封裝到構造器快取
以一個簡單的例項來理解整個構造器注入依賴的流程:constructor-arg解析封裝在ConstructorArgumentValues中,所以ConstructorArgumentValues有值時通過autowireConstructor方法選擇構造器進行例項化,優先選擇public作為候選構造器,獲取到依賴的屬性通過resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues)去建立依賴的sub例項,@Autowired用在構造器上主要是獲取候選構造器
public class Super {
private String name;
private Sub sub;
//構造器
public Super(String name, Sub sub) {
this.name = name;
this.sub = sub;
}
}
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
//當獲取getBean時開始例項化
Object aSuper = context.getBean("super");
<!--構造器方式注入constructor-arg-->
<bean id="super" class="cn.mywork.spring.Super">
<constructor-arg name="name" value="superName"/>
<constructor-arg name="sub" ref="sub"/>
</bean>
<!--注入的物件-->
<bean id="sub" class="cn.mywork.spring.Sub">
<property name="age" value="30"/>
</bean>
屬性自動裝配
如果是byName注入模式,則通過autowireByName方法呼叫getBean例項化依賴的Bean並注入到當前Bean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//PropertyValues對bean的屬性值的封裝,比如依賴的bean資訊
PropertyValues pvs = mbd.hasPropertyValues() ? mbd.getPropertyValues() : null;
/*AutowireMode自動裝配型別
int AUTOWIRE_NO = 0; 預設裝配模式,註解注入的方式
int AUTOWIRE_BY_NAME = 1; 通過beanName注入依賴
int AUTOWIRE_BY_TYPE = 2; 根據bean型別注入
int AUTOWIRE_CONSTRUCTOR = 3; 構造器注入
*/
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == 1 || resolvedAutowireMode == 2) {
MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);
if (resolvedAutowireMode == 1) {
/* 自動裝配byName,將sub注入到Super中,只需要保證sub的beanName和屬性名一致即可
public class Super{
private Sub sub1;
}
<bean id="super" class="com.xxx.Super" autowire="byName">
<bean id="sub1" class="com.xxx.Sub">
*/
//獲取依賴的屬性名稱作為beanName去getBean,再將依賴關係註冊到bean的dependy-on的快取中
this.autowireByName(beanName, mbd, bw, newPvs);
}
/* 自動裝配byType,通過sub屬性型別Sub.class去匹配sub的bean並進行註冊
通過doResolveDependency方法就是@Autowired查詢bean的第一個方式,找到class型別對應
的所有bean,再根據條件進行篩選的依賴的bean注入,並將依賴關係註冊到快取中
*/
if (resolvedAutowireMode == 2) {
this.autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
//執行存在InstantiationAwareBeanPostProcessor的postProcessProperties方法
//處理@Autowire標註的屬性注入
while(...) {
pvs = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
}
//property屬性注入
this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
}
註解@Autowired注入原理
回到doCreateBean,當構造器注入完成後繼續往下執行applyMergedBeanDefinitionPostProcessors(),這個方法用於處理MergedBeanDefinitionPostProcessor處理器的postProcessMergedBeanDefinition,實現該處理器會將合併的BeanDefinition作為方法的引數進行增強
這一步的主要作用就是將被@Autowired標註的set方法和欄位資訊封裝到metadata
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
//子類AutowiredAnnotationBeanPostProcessor的實現,處理@Autowired
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//在指定Bean中查詢使用@Autowire註解的元資料
//獲取欄位和set方法上的@Autowired註解資訊(不支援static修飾的欄位和方法)
//方法獲取descriptor.getWriteMethod()判斷是否為set方法
//method、required、pd封裝成AutowiredMethodElement新增到InjectionMetadata快取
InjectionMetadata metadata = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);
metadata.checkConfigMembers(beanDefinition);
}
回到populateBean方法,完成byName自動裝配後往下執行,通過postProcessProperties方法用於完成被@Autowired標註的屬性注入/方法注入,實現注入的方法inject()有兩個實現類,分別用於set方法和欄位屬性注入
protected void inject(Object target, String beanName, PropertyValues pvs) {}
欄位屬性注入優先通過屬性的name作為BeanName去找bean快取,如果沒有快取則根據classType去獲取bean,在doResolveDependency方法中會進行詳細查詢依賴bean的過程:根據名稱快速查詢快取,沒有快取則通過findAutowireCandidates根據型別 type 查詢名稱 beanNames作為候選,通過@Qualifier值進行篩選,和選擇候選構造器一樣;如果候選者個數大於1則繼續判斷@Primary(表示優先)和@Priority(數字越小優先順序越高),從而選出最終注入的bean
// 設定欄位訪問性
ReflectionUtils.makeAccessible(field);
// 通過反射為屬性賦值,將解析出來的bean例項賦值給field
field.set(bean, value);
@Resource先找預設的bean id(bean註冊的時候不指定beanId則預設為類的簡單名),如果介面有多個實現,則使用@Resource(name = “”)去指定,當注入的例項有多個實現類時,使用Resource
方法的注入:必須是set方法,在封裝metadata時就通過內省的方式判斷註解標註的方法是否為writeMethod(也就是set方法)
//內省機制
BeanInfo beanInfo = Introspector.getBeanInfo(superClass);
PropertyDescriptor[] ps = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : ps){
if (pd.getName().equals("name")){
//set方法
pd.getWriteMethod();
}
}
//設定set方法的訪問性
ReflectionUtils.makeAccessible(method);
//通過反射執行方法
method.invoke(bean, value);
PropertyValues屬性注入
populateBean方法最後一步applyPropertyValues將所有PropertyValues中的屬性填充到bean中,比如通過xml配置屬性依賴注入,在loadBeanDefinitions解析配置項時便將屬性值封裝在PropertyValues中
<!-- 配置setter屬性注入的標籤為property->
<bean id="student" class="cn.mywork.spring.Student">
<!--直接將值用value屬性填入-->
<property name="name" value="studentName"/>
<!--物件引入,需要ref去引入bean的id-->
<property name="sub" ref="sub"/>
<!--基本型別的陣列注入 array標籤-->
<property name="nums">
<array>
<value>1</value>
<value>2</value>
<value>3</value>
</array>
</property>
<!--物件集合的注入list標籤-->
<property name="subList">
<list>
<ref bean="sub"/>
<ref bean="sub"/>
</list>
</property>
<!--map集合的注入 map標籤-->
<property name="superMap">
<map>
<entry key="key1" value-ref="super"/>
<entry key="key2" value-ref="super"/>
</map>
</property>
</bean>
<!--注入的屬性-->
<bean id="sub" class="cn.mywork.spring.Sub">
<property name="age" value="20"/>
</bean>
<bean id="super" class="cn.mywork.spring.Super">
<property name="name" value="superName"/>
</bean>
解析配置項的property屬性型別,返回對應型別的值,核心方法就是setPropertyValues在很深入的內部進行實現,有BeanPropertyHandler方法注入和FieldPropertyHandler欄位注入兩種實現
//set方法進行屬性注入
ReflectionUtils.makeAccessible(writeMethod);
writeMethod.invoke(BeanWrapperImpl.this.getWrappedInstance(), new Object[]{value});
//欄位屬性注入
ReflectionUtils.makeAccessible(this.field);
this.field.set(DirectFieldAccessor.this.getWrappedInstance(), value);