[源碼系列:手寫spring] IOC第十三節:Bean作用域,增加prototype的支持
為了幫助大家更深入的理解bean的作用域,特意將BeanDefinition的雙例支持留到本章節中,創建Bean,相關Reader讀取等邏輯都有所改動。
內容介紹
在Spring中,Bean的作用域(Scope)定義了Bean的生命周期和可見性。包括單例和原型,在本章節中我們將為Bean添加多例的支持,下面是Prototype作用域的幾個特征介紹:
1. 多例(Prototype): Bean的prototype作用域表示每次從容器中獲取該Bean時都會創建一個新的實例。每個請求或依賴注入都會導致創建一個全新的Bean對象。
2. 不受Spring容器管理: prototype作用域的Bean實例不受Spring容器的管理,容器在創建Bean之后不會再跟蹤它。這意味著Spring容器不會負責釋放或銷毀prototype作用域的Bean。一旦Bean被創建并交給調用者,調用者負責Bean的生命周期,包括銷毀。
3. 適用場景: prototype作用域適用于那些每次獲取實例時都需要全新狀態的Bean,例如,HTTP請求的處理器或線程池中的任務。這樣可以確保每次獲取的Bean都是獨立的,不會影響其他實例。
這里設計到設計模式中的原型模式,形象地說,可以將prototype作用域的Bean比喻為一個不斷復制的模具。每次你需要一個新的Bean實例時,Spring容器會根據模具再次制作一個全新的Bean。這個模具本身不受容器管理,而是由你自己管理它的生命周期。這與singleton作用域的Bean不同,后者是像一個單一的實例化對象,由容器管理其生命周期。
prototype作用域
可見prototype類型的bean并不受spring容器的管理,你需要自己負責銷毀或釋放這些Bean實例,以防止內存泄漏。
代碼分支
核心代碼
BeanDefinition
private String scope = SCOPE_SINGLETON;
private boolean singleton = true;
private boolean prototype = false;
public static String SCOPE_SINGLETON = "singleton";
public static String SCOPE_PROTOTYPE = "prototype";
public void setScope(String scope) {
this.scope = scope;
this.singleton = SCOPE_SINGLETON.equals(scope);
this.prototype = SCOPE_PROTOTYPE.equals(scope);
}
public boolean isSingleton() {
return this.singleton;
}
public boolean isPrototype() {
return this.prototype;
}
AbstractAutowireCapableBeanFactory#doCreateBean()
...
protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition);
//為bean填充屬性
applyPropertyValues(beanName, bean, beanDefinition);
//執行bean的初始化方法和BeanPostProcessor的前置和后置處理方法
initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
//注冊有銷毀方法的bean
registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
if (beanDefinition.isSingleton()) {
addSingleton(beanName, bean);
}
return bean;
}
...
AbstractAutowireCapableBeanFactory#registerDisposableBeanIfNecessary()
/**
* 注冊有銷毀方法的bean,即bean繼承自DisposableBean或有自定義的銷毀方法
*
* @param beanName
* @param bean
* @param beanDefinition
*/
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
//只有singleton類型bean會執行銷毀方法
if (beanDefinition.isSingleton()) {
if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
}
}
}
測試
prototype-bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="car" class="bean.Car" scope="prototype">
<property name="name" value="Rolls-Royce"/>
</bean>
</beans>
單元測試
public class PrototypeBeanTest {
@Test
public void testPrototype() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:prototype-bean.xml");
Car car1 = applicationContext.getBean("car", Car.class);
Car car2 = applicationContext.getBean("car", Car.class);
System.out.println(car1 == car2);;
}
}
測試結果
false
Process finished with exit code 0

https://github.com/yihuiaa/little-spring
浙公網安備 33010602011771號