在【spring 源碼】IOC 之 ClassPathXmlApplicationContext 1-5 小段源碼裏屢次調用了getBean()的方法,咱們常常經過這個方法從beanFactory裏獲取bean實例,而bean的初始化細節也在這個方法裏實現了。本文重點解析getBean()方法。java
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
// L235
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 從手動註冊的單例緩存裏取出相關實例在下面的1-0展開細說
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//建立實例的第一種方式:正在建立的共享單例實例不爲空且是無參數的狀況(此時的單例對象並無真正實例化完畢,僅僅是提早曝光,解決循環依賴的策略)
...//打印相關日誌,略
// 下面這個方法:若是是普通 Bean 的話,直接返回 sharedInstance,
// 若是是 FactoryBean 的話,返回它建立的那個實例對象 詳見1-1
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//建立實例的第二種方式
// 當前線程已經建立過了此 beanName 的 prototype 類型的 bean,那麼拋異常.能調用到這裏的確定都是單例的
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 檢查當前父bean工廠是否存在該bean實例,若是不存在就遞歸調用直到有實例返回
String nameToLookup = originalBeanName(name);
if (args != null) {
// 有參數,這裏不展開詳說
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// 無參數建立實例
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
//將beanName放入alreadyCreated,標識其實例已經建立
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
getBean(dep);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
//這裏是第二種建立bean實例的方式,1-2展開詳說
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//非單例狀況,忽略
else if (mbd.isPrototype()) {
...
}
else {
...
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
...
}
}
return (T) bean;
}
複製代碼
這裏的getSingleton()調用了AbstractBeanFactory父類DefaultSingletonBeanRegistry#getSingleton()方法。spring
在此以前咱們先了解一下spring單例的三級緩存緩存
/** 已實例好單例對象緩存 爲了方便理解稱爲一級緩存(下同)*/
private final Map singletonObjects = new ConcurrentHashMap(256);
/** 提早曝光的單例對象緩存(還沒有實例完) 二級緩存*/
private final Map earlySingletonObjects = new HashMap(16);
/** 單例對象工廠緩存 三級緩存*/
private final Map> singletonFactories = new HashMap>(16);
複製代碼
DefaultSingletonBeanRegistry.java L172安全
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
/**
* Return the (raw) singleton object registered under the given name.
* Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* 大致意思是:返回一個以給定名稱註冊的單例對象,檢查已經實例好的單例池子,同時也容許對當前對象的引用
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//單例對象的cache
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//一級緩存裏沒有該對象而且此beanName正在建立過程當中纔會進來,由於正在建立的bean也許會在二級緩存裏
synchronized (this.singletonObjects) {
//二級緩存中取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//若是二級緩存裏沒有就從三級緩存裏取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//三級緩存裏不爲空就將其放入二級緩存裏,並將其從三級緩存裏移除
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
複製代碼
到這裏已經把spring 單例的三級緩存說完了,這三個緩存是spring處理循環依賴的重要依據,有興趣的話能夠看我以前的文章《spring是如何解決循環依賴的?》。bash
AbstractBeanFactory#getObjectForBeanInstance() L1607app
/**
* Get the object for the given bean instance, either the bean
* instance itself or its created object in case of a FactoryBean.
* 下面這個方法:若是是普通 Bean 的話,直接返回 sharedInstance,
* 若是是 FactoryBean 的話,返回它建立的那個實例對象
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
//若是這個bean不是工廠bean,直接拋異常,不讓其調用者撤銷引用工廠
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
//name以&開頭而且bean實例不屬於工廠bean,直接拋異常
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, //unless the caller actually wants a reference to the factory. if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { //①若是bean實例不是工廠bean,名稱是以&開頭,直接放回bean實例 //②若是bean實例是工廠bean,名稱不是以&開頭,直接放回bean實例 return beanInstance; } Object object = null; if (mbd == null) { //從factoryBeanObjectCache緩存裏取 object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // Return bean instance from factory. FactoryBean<?> factory = (FactoryBean<?>) beanInstance; if (mbd == null && containsBeanDefinition(beanName)) { //將該類的子類、父類配置信息都集中到rootBeanDefinition裏 mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); //下面調用了FactoryBeanRegistrySupport類的getObjectFromFactoryBean(),是從factoryBean裏獲取bean實例的入口 object = getObjectFromFactoryBean(factory, beanName,!synthetic); } return object; } 複製代碼
FactoryBeanRegistrySupport#getObjectFromFactoryBean() L98less
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
//單例場景
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
//這裏是實例化bean的最核心入口
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (object != null && shouldPostProcess) {
try {
//這裏會調用全部BeanPostProcessor#postProcessAfterInitialization的實現方法,這裏不作展開,後續會有文章介紹
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
//非單例場景,這裏不作展開
...
return object;
}
}
複製代碼
FactoryBeanRegistrySupport#doGetObjectFromFactoryBean() L148ide
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
//調用java的安全模型來實例化相關類,保證安全
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully // initialized yet: Many FactoryBeans just return null then. if (object == null && isSingletonCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException( beanName, "FactoryBean which is currently in creation returned null from getObject"); } return object; } 複製代碼
這裏只簡單說一下,後面會有專門一篇文章詳細介紹java的安全模型,感興趣的同窗能夠先參考《Java 受權內幕》,Java 安全模型介紹》,《Java安全——安全管理器、訪問控制器和類裝載器》先了解一下java的安全模型。post
小結一下,到這裏整個1-1第一種建立bean實例的方法結束了,接下來繼續回到AbstractBeanFactory#doGetBean()方法繼續往下看。ui
//AbstractAutowireCapableBeanFactory#createBean() L447
/**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
* @see #doCreateBean
*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
...
RootBeanDefinition mbdToUse = mbd;
//經過反射獲取指定beanName的類的字節碼,並將其賦值給mbdToUse的屬性
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
//檢查類的方法有無重寫,沒有重寫的設置AbstractBeanDefinition裏Overloaded爲false,避免後續的類型檢查的開銷
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
...
}
try {
// 若是重寫並註冊了BeanPostProcessor,在建立類以前生成類的代理並執行BeanPostProcessor的postProcessAfterInitialization()
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
...
}
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
...
}
return beanInstance;
}
複製代碼