共計 8577 個字符,預計需要花費 22 分鐘才能閱讀完成。
這篇文章主要介紹了 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 >
/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 實例對象”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注丸趣 TV 行業資訊頻道。