Bean的做用域java
默認狀況下,bean的做用域爲單例模式(singleton):spring
在applicationContext建立時,就將配置文件中的bean加載完畢;app
在調用getBean時,從applicationContext中獲取;less
也就是說,在整個應用程序中,bean只存在一個實例,下面寫一段代碼測試一下,寫一個Car類,有一個Name字段:ide
package cn.net.bysoft.lesson4; public class Car { public Car() { } @Override public String toString() { return "Car [name=" + name + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } private String name; }
在配置文件中,配置這個Car的bean元素:函數
<bean id="car" class="cn.net.bysoft.lesson4.Car"> </bean>
@Test public void testScopeIsDefault() { // 在Spring容器初始化時就生成了bean對應的對象。 // 在調用時,從Spring容器中get一個對象,這個對象是單例的。 Car car = (Car) ctx.getBean("car"); car.setName("Audi"); Car car1 = (Car) ctx.getBean("car"); car1.setName("BMW"); // get到的對象都會修改這個單例的bean。 System.out.println(car); System.out.println(car1); /** * output: * Car [name=BMW] * Car [name=BMW] * */ }
測試發現,對car設置的name值被car1覆蓋了,也就是說,car與car1實際是使用的同一個car實例,car==car1。post
能夠改變bean的做用域來解決此問題,將scope=prototype:測試
<bean id="car2" class="cn.net.bysoft.lesson4.Car" scope="prototype"> </bean>
@Test public void testScopeIsPrototype() { // 設置了bean的scope=prototype後 // 在Spring容器初始化時不會自動生成bean對應的對象 // 而是在get時生成對象,對象不是單例的。 Car car = (Car) ctx.getBean("car2"); car.setName("Audi"); Car car1 = (Car) ctx.getBean("car2"); car1.setName("BMW"); System.out.println(car); System.out.println(car1); /** * output: * Car [name=Audi] * Car [name=BMW] * */ }
Bean的生命週期this
正常狀況下,spring加載bean時,首先會調用構造函數,接着對property賦值時調用setter方法。spa
若是須要對bean有更多的控制,能夠設置init-method與destroy-method屬性,修改一下car對象,加入init與destory方法:
package cn.net.bysoft.lesson4; public class Car { public Car() { System.out.println("1.執行了構造函數。"); } public void init() { System.out.println("3.執行初始化。"); } public void destory() { System.out.println("5.執行銷燬。"); } @Override public String toString() { System.out.println("4.使用bean方法。"); return "Car [name=" + name + "]"; } public String getName() { return name; } public void setName(String name) { System.out.println("2.調用setter方法。"); this.name = name; } private String name; }
在配置文件中爲bean配置init-method與destory-method:
<bean id="car3" class="cn.net.bysoft.lesson4.Car" init-method="init" destroy-method="destory" scope="singleton"> <property name="name" value="Audi"></property> </bean>
在進行測試,看看各個方法的執行順序:
@Test public void testCycle() { Car car = (Car) ctx.getBean("car3"); System.out.println(car); ctx.close(); }
執行了構造函數
執行了setter()方法
執行了init()方法
執行了destory()方法
使用bean的後置處理器
上面的作法是爲單個類進行更多的初始化控制,還能夠配置全局的初始化控制,作法爲,建立一個類使用實現BeanPostProcessor接口,將該類配置到spring配置文件中便可:
package cn.net.bysoft.lesson4; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { @Override // 後置初始化處理 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("after..." + bean.getClass() + ", " + beanName); return bean; } @Override // 前置初始化處理 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("before..." + bean.getClass() + ", " + beanName); return bean; } }
<bean id="car4" class="cn.net.bysoft.lesson4.Car" init-method="init" destroy-method="destory" scope="singleton"> <property name="name" value="BMW"></property> </bean> <bean class="cn.net.bysoft.lesson4.MyBeanPostProcessor"></bean>
@Test public void testBeanPostProcessor() { Car car = (Car) ctx.getBean("car4"); System.out.println(car); ctx.close(); }
經過結果能夠看到,配置的處理器before在init方法前被調用,after在init方法後調用。