一般,咱們稱BeanFactory爲SpringIOC的基礎容器ApplicationContext是容器的⾼級接⼝,⽐BeanFactory要擁有更多的功能,好比說國際化支持和資源訪問(xml,java配置類)等等java
Java環境下啓動IOC容器spring
在spring框架管理Bean對象的建立時,Bean對象默認都是單例的,可是它⽀持配置的⽅式改變做⽤範圍。做⽤範圍官⽅提供的說明以下圖:數據庫
在上圖中提供的這些選項中,咱們實際開發中⽤到最多的做⽤範圍就是singleton(單例模式)和prototype(原型模式,也叫多例模式)。配置⽅式參考下⾯的代碼:服務器
<!--配置service對象--> <bean id="transferService" class="com.lagou.service.impl.TransferServiceImpl" scope="singleton"> </bean>
⼀句話總結:單例模式的bean對象⽣命週期與容器相同
⼀句話總結:多例模式的bean對象,spring框架只負責建立,不負責銷燬
在基於xml的IoC配置中,bean標籤是最基礎的標籤。它表示了IoC容器中的⼀個對象。換句話說,若是⼀個對象想讓spring管理,在XML的配置中都須要使⽤此標籤配置,Bean標籤的屬性以下:app
依賴注⼊分類框架
按照注⼊的⽅式分類ide
按照注⼊的數據類型分類函數
注意:性能
哪些bean的定義寫在xml中,哪些bean的定義使⽤註解測試
第三⽅jar中的bean定義在xml,⽐如德魯伊數據庫鏈接池,⾃⼰開發的bean定義使⽤註解
xml形式 | 對應的註解形式 |
---|---|
標籤 | @Component("accountDao"),註解加在類上bean的id屬性內容直接配置在註解後⾯若是不配置,默認定義個這個bean的id爲類的類名⾸字⺟⼩寫;另外,針對分層代碼開發提供了@Componenet的三種別名@Controller、@Service、@Repository分別⽤於控制層類、服務層類、dao層類的bean定義,這四個註解的⽤法徹底⼀樣,只是爲了更清晰的區分⽽已 |
標籤的scope屬性 | @Scope("prototype"),默認單例,註解加在類上 |
標籤的init- method屬性 | @PostConstruct,註解加在⽅法上,該⽅法就是初始化後調⽤的⽅法 |
標籤的destory- method屬性 | @PreDestory,註解加在⽅法上,該⽅法就是銷燬前調⽤的⽅法 |
Bean的延遲加載(延遲建立)
ApplicationContext容器的默認⾏爲是在啓動服務器時將全部 singletonbean提早進⾏實例化。提早實例化意味着做爲初始化過程的⼀部分,ApplicationContext實例會建立並配置全部的singleton bean
⽐如:
<bean id="testBean" class="cn.boc.LazyBean" /> 該bean默認的設置爲: <bean id="testBean" class="cn.boc.LazyBean" lazy-init="false" />
lazy-init="false",⽴即加載,表示在spring啓動時,⽴刻進⾏實例化,若是使用註解則爲@Lazy,默認參數就是true
import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @Component @Lazy public class BeanExp { }
若是不想讓⼀個singleton bean 在 ApplicationContext實現初始化時被提早實例化,那麼能夠將bean設置爲延遲實例化
<bean id="testBean" class="cn.boc.LazyBean" lazy-init="false" />
設置 lazy-init爲true
的 bean將不會在 ApplicationContext啓動時提早被實例化,⽽是第⼀次向容器經過 getBean索取 bean時實例化的
若是⼀個設置了⽴即加載的 bean1,引⽤了⼀個延遲加載的 bean2 ,那麼 bean1 在容器啓動時被實例化,⽽ bean2 因爲被 bean1 引⽤,因此也被實例化,這種狀況也符合延時加載的 bean 在第⼀次調⽤時才被實例化的規則
也能夠在容器層次中經過在 元素上使⽤ "default-lazy-init" 屬性來控制延時初始化。以下⾯配置:
<beans default-lazy-init="true"> <!-- no beans will be eagerly pre-instantiated... --> </beans>
若是⼀個 bean 的 scope 屬性爲 scope="pototype"
時,即便設置了 lazy-init="false"
,容器啓動時也不會實例化bean,⽽是調⽤ getBean ⽅法實例化的
Bean建立的三種⽅式中的靜態⽅法和實例化⽅法和FactoryBean做⽤相似,FactoryBean使⽤較多,尤爲在Spring框架⼀些組件中會使⽤,還有其餘框架和Spring框架整合時使⽤
public class BeanExp3 { String name; String address; int type; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getType() { return type; } public void setType(int type) { this.type = type; } @Override public String toString() { return "BeanExp3{" + "name='" + name + '\'' + ", address='" + address + '\'' + ", type=" + type + '}'; } }
import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class MyFactoryBean implements FactoryBean<BeanExp3> { @Value("測試Bean,中環大廈,1") public String info; @Override public BeanExp3 getObject() throws Exception { System.out.println("info:" + info); BeanExp3 beanExp3 = new BeanExp3(); String[] array = info.split(","); beanExp3.setName(array[0]); beanExp3.setAddress(array[1]); beanExp3.setType(Integer.valueOf(array[2])); return beanExp3; } @Override public Class<?> getObjectType() { return BeanExp.class; } }
<bean id="BeanExp3" class="com.boc.MyFactoryBean"> <property name="companyInfo" value="測試Bean,中環大廈,1"/> </bean>
Object beanExp3 = appcationContext.getBean("myFactoryBean"); System.out.println(beanExp3);
須要在id以前添加「&」
Object beanExp3 = appcationContext.getBean("&myFactoryBean"); System.out.println(beanExp3);
Spring提供了兩種後處理bean的擴展接⼝,分別爲 BeanPostProcessor和BeanFactoryPostProcessor,二者在使⽤上是有所區別的
⼯⼚初始化(BeanFactory)—> Bean對象
在BeanFactory初始化以後可使⽤BeanFactoryPostProcessor進⾏後置處理作⼀些事情
在Bean對象實例化(並非Bean的整個⽣命週期完成)以後可使⽤BeanPostProcessor進⾏後置處理作⼀些事情
注意:對象不⼀定是springbean,⽽springbean⼀定是個對象
SpringBean的⽣命週期
BeanPostProcessor是針對Bean級別的處理,能夠針對某個具體的Bean
該接⼝提供了兩個⽅法,分別在Bean的初始化⽅法前和初始化⽅法後執⾏,具體這個初始化⽅法指的是 什麼⽅法,相似咱們在定義bean時,定義了init-method所指定的⽅法
定義⼀個類實現了BeanPostProcessor,默認是會對整個Spring容器中全部的bean進⾏處理。若是要對 具體的某個bean處理,能夠經過⽅法參數判斷,兩個類型參數分別爲Object和String,第⼀個參數是每一個bean的實例,第⼆個參數是每一個bean的name或者id屬性的值。因此咱們能夠經過第⼆個參數,來判斷咱們將要處理的具體的bean。
注意:處理是發⽣在Spring容器的實例化和依賴注⼊以後。
BeanFactory級別的處理,是針對整個Bean的⼯⼚進⾏處理,典型應
⽤:PropertyPlaceholderConfigurer
此接⼝只提供了⼀個⽅法,⽅法參數爲ConfigurableListableBeanFactory,該參數類型定義了⼀些⽅法
其中有個⽅法名爲getBeanDefinition的⽅法,咱們能夠根據此⽅法,找到咱們定義bean的BeanDefinition對象。而後咱們能夠對定義的屬性進⾏修改,如下是BeanDefinition中的⽅法
⽅法名字相似咱們bean標籤的屬性,setBeanClassName對應bean標籤中的class屬性,因此當咱們拿到BeanDefinition對象時,咱們能夠⼿動修改bean標籤中所定義的屬性值。
BeanDefinition對象:咱們在XML中定義的bean標籤,Spring解析bean標籤成爲⼀個JavaBean,這個JavaBean就是BeanDefinition
注意:調⽤ BeanFactoryPostProcessor ⽅法時,這時候bean尚未實例化,此時 bean 剛被解析成BeanDefinition對象