Object getBean(String name) 메소드 구현 살펴보기-윗 부분
먼저 소스코드를 보겠습니다.
public Object getBean(String name) throws BeansException {
return getBean(name, null, null);
}
1231377222.bmp
아.. 다른 메소드를 호출 하고 있습니다. 혹시 getBean(String name, Class requiredType) 메소드도 이러한 모습을 하고 있지 않을까 예상됩니다.
public Object getBean(String name, Class requiredType) throws BeansException {
return getBean(name, requiredType, null);
}
1022700860.bmp
역시 같은 모습을 하고 있었습니다.
이번 글에서는 두 개의 메소드 구현을 한꺼번에 살펴볼 수 있게 됐습니다. :) 이거양득?
먼저 세개의 아규먼트들이 무엇에 사용되는지 주석을 보겠습니다.
/**
* Return the bean with the given name,
* checking the parent bean factory if not found.
* @param name the name of the bean to retrieve
* @param requiredType the required type of the bean to retrieve
* @param args arguments to use if creating a prototype using explicit arguments to a
* static factory method. It is invalid to use a non-null args value in any other case.
*/
name과 class는 알겠는데 args 라는 final Object[] 타입이 무엇인지 잘 모르겠네요. 정적 팩토리 메소드를 사용해서prototype을 생성할 때 사용할 아규먼트들이라고 합니다.
Object getBean(String name, Class requiredType, final Object[] args) 메소드 보기
[#M_ more.. | less.. |
public Object getBean(String name, Class requiredType, final Object[] args) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean = null;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null) {
if (isSingletonCurrentlyInCreation(beanName)) {
if (logger.isDebugEnabled()) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
if (containsBeanDefinition(beanName)) {
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(beanName, false);
bean = getObjectForBeanInstance(sharedInstance, name, mergedBeanDefinition);
}
else {
bean = getObjectForBeanInstance(sharedInstance, name, null);
}
}
else {
// Fail if we're already creating this singleton instance:
// We're assumably within a circular reference.
if (isSingletonCurrentlyInCreation(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 (parentBeanFactory instanceof AbstractBeanFactory) {
// Delegation to parent with args only possible for AbstractBeanFactory.
return ((AbstractBeanFactory) parentBeanFactory).getBean(nameToLookup, requiredType, args);
}
else if (args == null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
throw new NoSuchBeanDefinitionException(beanName,
"Cannot delegate to parent BeanFactory because it does not supported passed-in arguments");
}
}
this.alreadyCreated.add(beanName);
final RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(beanName, false);
checkMergedBeanDefinition(mergedBeanDefinition, beanName, args);
// Create bean instance.
if (mergedBeanDefinition.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
try {
return createBean(beanName, mergedBeanDefinition, 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, mergedBeanDefinition);
}
else if (mergedBeanDefinition.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mergedBeanDefinition, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, mergedBeanDefinition);
}
else {
String scopeName = mergedBeanDefinition.getScope();
final Scope 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 {
Object bean = createBean(beanName, mergedBeanDefinition, args);
if (requiresDestruction(bean, mergedBeanDefinition)) {
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mergedBeanDefinition, getBeanPostProcessors()));
}
return bean;
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, mergedBeanDefinition);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active", ex);
}
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isAssignableFrom(bean.getClass())) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return bean;
}
_M#]
헉.... 깁니다....
메소드를 가장 밖에 있는 if 문을 기준으로 삼등분 시키겠습니다.
상
[#M_ more.. | less.. |
public Object getBean(String name, Class requiredType, final Object[] args) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean = null;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (logger.isDebugEnabled()) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(beanName, false);
bean = getObjectForBeanInstance(sharedInstance, name, mergedBeanDefinition);
} else {
bean = getObjectForBeanInstance(sharedInstance, name, null);
}
}
_M#]
세 부분으로 나누니까 그래도 조금 안심이 되네요. 하지만 여전히 중간 부분이 굉장히 크네요. 먼저 제일 윗 부분 부터 살펴보겠습니다.
이 부분은 getSingleton(String) 메소드를 호출한 결과 값이 null이 아닐 경우에 실행되는 부분입니다. 그리고 크게 두 부분으로 나뉘어 지는데 첫번째 부분은 메소드 이름으로 추정해 보건데 싱글톤 객체가 현재 생성 중일 때 또는 그렇지 않을 때 logging 메시지를 처리하는 부분이라고 생각됩니다.
다음 부분은 실질적으로 빈을 생성하는 부분인듯 합니다. 빈 이름에 해당하는 빈 정의가 존재할 때와 그렇치 않을 때 각각 getObjectForBeanInstance()를 통해 bean을 받아 오고 있습니다.
이전에도 몇 번 본적이 있는 transformedBeanName(String) 메소드입니다.
[#M_ more.. | less.. |
protected String transformedBeanName(String name) {
String beanName = BeanFactoryUtils.transformedBeanName(name);
// Handle aliasing.
synchronized (this.aliasMap) {
String canonicalName = (String) this.aliasMap.get(beanName);
return (canonicalName != null ? canonicalName : beanName);
}
}
_M#]
Object sharedInstance = getSingleton(beanName); 여기서 호출되는 getSingleton(String)메소드 입니다. 이 메소드는 DefaultSingletonBeanRegistry 클래스에 있습니다. DefaultSingletonBeanRegistry 클래스와 AbstractBeanFactory와의 관계는 바로 다른 글에서 언급이 되었습니다. 짧게 D가 A의 아버지 입니다.
[#M_ more.. | less.. |
//DefaultSingletonBeanRegistry class
public Object getSingleton(String beanName) {
synchronized (this.singletonCache) {
return this.singletonCache.get(beanName);
}
}
_M#]
logging 관련 부분은 나중에 살펴보도록 하고 getMergedBeanDefinition(String, boolean) 메소드를 보겠습니다.
[#M_ more.. | less.. |
/**
* Return a RootBeanDefinition, even by traversing parent if the parameter is a
* child definition. Can ask the parent bean factory if not found in this instance.
* @param name the name of the bean to retrieve the merged definition for
* @param includingAncestors whether to ask the parent bean factory if not found
* in this instance
* @return a (potentially merged) RootBeanDefinition for the given bean
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
* @throws BeanDefinitionStoreException in case of an invalid bean definition
*/
protected RootBeanDefinition getMergedBeanDefinition(String name, boolean includingAncestors)
throws BeansException {
String beanName = transformedBeanName(name);
// Efficiently check whether bean definition exists in this factory.
if (includingAncestors && !containsBeanDefinition(beanName) &&
getParentBeanFactory() instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName, true);
}
// Resolve merged bean definition locally.
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
_M#]
마지막으로 getObjectForBeanInstance(Object, String, RootBeanDifinition) 메소드를 살펴보겠습니다.
[#M_ more.. | less.. |
/**
* Get the object for the given bean instance, either the bean
* instance itself or its created object in case of a FactoryBean.
* @param beanInstance the shared bean instance
* @param name name that may include factory dereference prefix
* @param mbd the merged bean definition
* @return the object to expose for the bean
*/
protected Object getObjectForBeanInstance(Object beanInstance, String name, RootBeanDefinition mbd) throws BeansException {
String beanName = transformedBeanName(name);
// Don't let calling code try to dereference the
// bean factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
boolean shared = (mbd == null || mbd.isSingleton());
Object object = beanInstance;
// 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) {
if (!BeanFactoryUtils.isFactoryDereference(name)) {
// Return bean instance from factory.
FactoryBean factory = (FactoryBean) beanInstance;
if (logger.isDebugEnabled()) {
logger.debug("Bean with name '" + beanName + "' is a factory bean");
}
// Cache object obtained from FactoryBean if it is a singleton.
if (shared && factory.isSingleton()) {
synchronized (this.factoryBeanObjectCache) {
object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = getObjectFromFactoryBean(factory, beanName, mbd);
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
else {
object = getObjectFromFactoryBean(factory, beanName, mbd);
}
}
else {
// The user wants the factory itself.
if (logger.isDebugEnabled()) {
logger.debug("Calling code asked for FactoryBean instance for name '" + beanName + "'");
}
}
}
return object;
}
_M#]
getObjectForBeanInstance 메소드는 좀 더 자세히 살펴 봐야겠습니다.