在使用spring時,可能會遇到這種情況:乙個單例的bean依賴另乙個非單例的bean。如果簡單的使用自動裝配來注入依賴,就可能會出現一些問題,如下所示:
@component
public class classa
}
@component
@scope(value = scope_prototype)
public class classb
}
這裡class a
採用了預設的單例scope,並依賴於class b
, 而class b
的scope是prototype
,因此不是單例的,這時候跑個測試就看出這樣寫的問題:
@runwith(springrunner.class)
@contextconfiguration(classes = )
public class mytest
}}
輸出的結果是:
this is class a: classa@282003e1
this is class b: classb@7fad8c79
this is class a: classa@282003e1
this is class b: classb@7fad8c79
this is class a: classa@282003e1
this is class b: classb@7fad8c79
可以看到,兩個類的hash code在三次輸出中都是一樣。class a
的值不變是可以理解的,因為它是單例的,但是class b
的scope是prototype
卻也保持hash code不變,似乎也成了單例?
產生這種的情況的原因是,class a
的scope是預設的singleton
,因此context
只會建立class a
的bean一次,所以也就只有一次注入依賴的機會,容器也就無法每次給class a
提供乙個新的class b
。
@component
public void printclass()
public classb getclassb()
}}
這樣就能夠在每次需要到class b
的時候手動去context
裡找到新的bean。再跑一次測試後得到了以下輸出:
this is class a: com.devhao.classa@4df828d7
this is class b: com.devhao.classb@31206beb
this is class a: com.devhao.classa@4df828d7
this is class b: com.devhao.classb@3e77a1ed
this is class a: com.devhao.classa@4df828d7
this is class b: com.devhao.classb@3ffcd140
可以看到class a
的hash code
在三次輸出中保持不變,而class b
的卻每次都不同,說明問題得到了解決,每次呼叫時用到的都是新的例項。
但是這樣的寫法就和spring強耦合在一起了,spring提供了另外兩種方法來降低侵入性。
spring提供了乙個名為@lookup
的註解,這是乙個作用在方法上的註解,被其標註的方法會被重寫,然後根據其返回值的型別,容器呼叫beanfactory
的getbean()
方法來返回乙個bean。
@component
public class classa
@lookup
public classb getclassb()
}
可以發現簡潔了很多,而且不再和spring強耦合,再次執行測試依然可以得到正確的輸出。
被標註的方法的返回值不再重要,因為容器會動態生成乙個子類然後將這個被註解的方法重寫/實現,最終呼叫的是子類的方法。
使用的@lookup
的方法需要符合如下的簽名:
[abstract] themethodname(no-arguments);
spring還提供了另外一種方法來解決這個問題。簡單來說就是如果乙個bean a
對另外乙個作用域更短的bean b
有依賴,那麼在例項化bean a
並注入依賴時,注入的不是bean b
本身,而是乙個aop**,這個**可以找到實際的bean
。
@component
public class classa
}
@component
@scope(value = scope_prototype, proxymode = scopedproxymode.target_class)
public class classb
}
可以看出,使用這種方法的好處是僅需對bean b
進行簡單的配置,並且bean a
根本不用意識到**的存在,將bean b
當做乙個正常的bean
來裝載就好。 spring 生命週期
spring 生命週期 ioc容器 1 載入配置檔案 2 資源定位 3 資源解析 4 生成beandefinition元資訊 5 通過工廠把beandefinition載入到容器中 初始化bean例項,由spring產生的bean預設是單例的 依賴注入,就是處理的,bean引用bean的問題 ioc...
Spring 生命週期
public void refresh throws bean ception,illegalstateexception catch bean ception ex 1.preparerefresh 用於設定spring啟動時間並且設定active flag 為true 2.configurabl...
Spring生命週期
1.容器啟動,例項化所有實現了beanfactorypostprocessor介面的類.它會在任何普通bean例項化之前載入.2.例項化剩下的bean,對這些bean進行依賴注入.3.如果bean有實現beannameaware的介面那麼對這些bean進行呼叫 4.如果bean有實現beanfact...