您好,登錄后才能下訂單哦!
這篇文章主要介紹了Spring這么初始化Bean實例對象的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Spring這么初始化Bean實例對象文章都會有所收獲,下面我們一起來看看吧。
代碼入口
DefaultListableBeanFactory的preInstantiateSingletons方法
DefaultListableBeanFactory的preInstantiateSingletons方法,顧名思義,初始化所有的單例Bean,看一下方法的定義:
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isInfoEnabled()) {
this.logger.info("Pre-instantiating singletons in " + this);
}
synchronized (this.beanDefinitionMap) {
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return ((SmartFactoryBean) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
}
}
前面的代碼比較簡單,根據beanName拿到BeanDefinition(即Bean的定義)。由于此方法實例化的是所有非懶加載的單例Bean,因此要實例化Bean,必須滿足11行的三個定義:
(1)不是抽象的
(2)必須是單例的
(3)必須是非懶加載的
接著簡單看一下第12行~第29行的代碼,這段代碼主要做的是一件事情:首先判斷一下Bean是否FactoryBean的實現,接著判斷Bean是否SmartFactoryBean的實現,假如Bean是SmartFactoryBean的實現并且eagerInit(這個單詞字面意思是渴望加載,找不到一個好的詞語去翻譯,意思就是定義了這個Bean需要立即加載的意思)的話,會立即實例化這個Bean。Java開發人員不需要關注這段代碼,因為SmartFactoryBean基本不會用到,我翻譯一下Spring官網對于SmartFactoryBean的定義描述:
FactoryBean接口的擴展接口。接口實現并不表示是否總是返回單獨的實例對象,比如FactoryBean.isSingleton()實現返回false的情況并不清晰地表示每次返回的都是單獨的實例對象
不實現這個擴展接口的簡單FactoryBean的實現,FactoryBean.isSingleton()實現返回false總是簡單地告訴我們每次返回的都是單獨的實例對象,暴露出來的對象只能夠通過命令訪問
注意:這個接口是一個有特殊用途的接口,主要用于框架內部使用與Spring相關。通常,應用提供的FactoryBean接口實現應當只需要實現簡單的FactoryBean接口即可,新方法應當加入到擴展接口中去
代碼示例
為了后面的代碼分析方便,事先我定義一個Bean:
package org.xrq.action;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
public class MultiFunctionBean implements InitializingBean, BeanNameAware, BeanClassLoaderAware {
private int propertyA;
private int propertyB;
public int getPropertyA() {
return propertyA;
}
public void setPropertyA(int propertyA) {
this.propertyA = propertyA;
}
public int getPropertyB() {
return propertyB;
}
public void setPropertyB(int propertyB) {
this.propertyB = propertyB;
}
public void initMethod() {
System.out.println("Enter MultiFunctionBean.initMethod()");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("Enter MultiFunctionBean.setBeanClassLoader(ClassLoader classLoader)");
}
@Override
public void setBeanName(String name) {
System.out.println("Enter MultiFunctionBean.setBeanName(String name)");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Enter MultiFunctionBean.afterPropertiesSet()");
}
@Override
public String toString() {
return "MultiFunctionBean [propertyA=" + propertyA + ", propertyB=" + propertyB + "]";
}
}
定義對應的spring.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="multiFunctionBean" class="org.xrq.action.MultiFunctionBean" init-method="initMethod" />
</beans>
利用這個MultiFunctionBean,我們可以用來探究Spring加載Bean的多種機制。
doGetBean方法構造Bean流程
上面把getBean之外的代碼都分析了一下,看代碼就可以知道,獲取Bean對象實例,都是通過getBean方法,getBean方法最終調用的是DefaultListableBeanFactory的父類AbstractBeanFactory類的doGetBean方法,因此這部分重點分析一下doGetBean方法是如何構造出一個單例的Bean的。
看一下doGetBean方法的代碼實現,比較長:
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;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
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 dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
try {
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()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
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",
ex);
}
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
關于“Spring這么初始化Bean實例對象”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Spring這么初始化Bean實例對象”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。