基本流程
完成了XML配置文件的解析,接下來就是對bean加載的探索。
//2.從ioc容器中獲取bean實例
MyTestBean myTestBean = (MyTestBean) beanFactory.getBean("myTestBean");
跟蹤進Spring的源碼
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
// 1. 提取對應的beanName
final String beanName = this.transformedBeanName(name);
// 2. 直接嘗試從緩存獲取或者singletonFactories中的ObjectFactory中獲取
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if (sharedInstance != null && args == null) {
if (this.logger.isDebugEnabled()) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 3.返回對應的實例,有時候存儲諸如BeanFactory的情況並不是直接返回實例本身而是返回指定方法返回的實例
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
// 4.
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = this.getParentBeanFactory();
// 5.如果beanDefinitionMap中也就是在所有已經加載的類中不包括beanName,則嘗試從parentBeanFactory中檢測
if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
// 遞歸到BeanFactory中尋找
if (args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
}
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
// 如果不是僅僅做類型檢查則是創建bean,這裏要進行記錄
if (!typeCheckOnly) {
this.markBeanAsCreated(beanName);
}
try {
// 6.將存儲XML配置文件的GernericBeanDefinition轉換爲RootBeanDefinition,如果指定BeanName是子Bean的話同時會合並父類的相關屬性
final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var11;
// 7.若存在依賴則需要遞歸實例化依賴的bean
if (dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length;
for(int var13 = 0; var13 < var12; ++var13) {
String dep = var11[var13];
if (this.isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 緩存依賴調用
this.registerDependentBean(dep, beanName);
this.getBean(dep);
}
}
// 8.singleton模式的創建
if (mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return AbstractBeanFactory.this.createBean(beanName, mbd, args);
} catch (BeansException var2) {
AbstractBeanFactory.this.destroySingleton(beanName);
throw var2;
}
}
});
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
// prototype模式的創建
var11 = null;
Object prototypeInstance;
try {
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
// 指定的scope是實例化bean
String scopeName = mbd.getScope();
Scope scope = (Scope)this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
AbstractBeanFactory.this.beforePrototypeCreation(beanName);
Object var1;
try {
var1 = AbstractBeanFactory.this.createBean(beanName, mbd, args);
} finally {
AbstractBeanFactory.this.afterPrototypeCreation(beanName);
}
return var1;
}
});
bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException var21) {
throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", var21);
}
}
} catch (BeansException var23) {
this.cleanupAfterBeanCreationFailure(beanName);
throw var23;
}
}
// 9.檢查需要的類型是否符合bean的實際類型
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return this.getTypeConverter().convertIfNecessary(bean, requiredType);
} catch (TypeMismatchException var22) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var22);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
} else {
return bean;
}
}
- 轉換對應beanName
在beanFactory.getBean(String name)
傳入的參數,可能是別名,可能是beanName,也可能是FactoryBean,所以需要進行一系列的解析 - 嘗試從緩存中加載單例
單例在Spring的同一個容器內只會被創建一次,後續再獲取bean,就直接從單例緩存中獲取了。如果獲取不成功,則再次嘗試從singletonFactories中加載。因爲在創建bean的時候會存在依賴注入的情況,而在創建依賴的時候爲了避免循環依賴,在Spring中創建bean的原則是不等bean創建完成就會創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建時候需要依賴上一個bean則直接使用ObjectFactory - bean的實例化
如果從緩存中得到了bean的原始狀態,則需要對bean進行實例化。這裏需要說明:緩存中記錄的只是最原始的bean狀態,並不一定是我們最終想要的bean。而getObjectForBeanInstance
就是完成這個工作的 - 原型模式的依賴檢查
只有在單例情況下才會嘗試解決循環依賴,如果存在A中有B的屬性,B中有A的屬性,那麼當依賴注入的時候,就會產生A還未創建完的時候因爲對於B的創建再次返回創建A,造成循環依賴,也就是情況isPrototypeCurrentlyInCreation(beanName)
判斷true - 檢查parentBeanFactory
如果緩存沒有數據的話直接轉到父類工程上去加載 - 將存儲XML配置文件的GernericBeanDefinition轉換爲RootBeanDefinition
因爲從XML配置文件中讀取到的Bean信息是存儲在GernericBeanDefinition中的,但是所有的Bean後續處理都是針對於RootBeanDefinition的,所以這裏需要進行一個轉換,轉換的同時如果父類bean不爲空的話,則會一併合併父類的屬性 - 尋找依賴
因爲bean的初始化過程中很可能會用到某些屬性,而某些屬性很可能是動態配置的,並且配置成依賴於其他的bean,那麼這個時候就有必要先加載依賴的bean,所以,在Spring的加載順序中,在初始化某一個bean的時候首先會初始化這個bean所對應的依賴 - 針對不同的scope進行bean的創建
Spring中存在着不同的備scope,其中默認的是singleton,但是還有些其他的配置諸如prototype、request之類的。在這個步驟中,Spring會根據不同的配置進行不同的初始化策略 - 類型轉換
將生產的bean,轉換爲參數requiredType的類型。
FactoryBean
一般情況下,Spring通過反射機制利用bean的class屬性指定實現類來實例化bean。
除此之外,Spring還提供了一個org.springframework.bean.factory.FactoryBean的工廠類接口,用戶可以通過實現該接口定製實例化bean的邏輯。FactoryBean接口對於Spring來說很重要,它隱藏了實例化一些複雜bean的細節。
public interface FactoryBean<T> {
// 返回由FactoryBean創建的bean實例
// 如果isSingleton()返回true,則該實例會放到Spring容器中單實例緩存池中
T getObject() throws Exception;
// 返回FactoryBean創建的bean類型
Class<?> getObjectType();
// 返回由FactoryBean創建的bean實例的作用域是singleton還是prototype
boolean isSingleton();
}
當配置文件中<bean>
的class屬性配置的實現類是FactoryBean時,通過getBean()方法返回的不是FactoryBean本身,而是FactoryBean.getObject()方法所返回的對象,相當於FactoryBean.getObject()代理了getBean()方法
public class Car {
private int maxSpeed;
private String brand;
private double price;
// get/set
}
如果使用傳統方式配置Car的時候,Car的每個屬性分別對應一個<property>
元素標籤
如果用FactoryBean的方式實現就會靈活一些
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo;
public Car getObject() throws Exception {
Car car = new Car();
String[] infos = carInfo.split(",");
car.setBrand(infos[0]);
car.setMaxSpeed(Integer.valueOf(infos[1]));
car.setPrice(Double.valueOf(infos[2]));
return car;
}
public Class<Car> getObjectType() {
return Car.class;
}
public boolean isSingleton() {
return false;
}
public String getCarInfo() {
return this.carInfo;
}
public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
}
有了這個CarFactoryBean後,就可以如下配置了
<bean id="car" class="com.whyalwaysmea.factorybean.CarFactoryBean" >
<property name="carInfo" value="超級跑車,400,20000000" />
</bean>
當調用getBean("car")
時,Spring通過反射機制發現CarFactoryBean實現了FactoryBean的接口,這時Spring容器就調用接口方法CarFactoryBean.getObject()方法返回。
如果希望獲取CarFacoryBean的實例,則調用getBean("&car")