Object getBean(String name) 메소드 구현 살펴보기-중간 부분
return getBean(name, null, null);
}
위에서 보시다시피 getBean(String) 메소드에서 호출하는
public Object getBean(String name, Class requiredType, final Object[] args) throws BeansException
이 메소드의 중간 부분을 살펴 볼 차례입니다.(이 메소드의 윗부분은 전에 살펴 보았습니다.)
코드보기
[#M_ more.. | less.. |
else {
// Fail if we're already creating this singleton instance:
// We're assumably within a circular reference.
throw new BeanCurrentlyInCreationException(beanName);
}
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 forAbstractBeanFactory.
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");
}
}
final RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(beanName, false);
checkMergedBeanDefinition(mergedBeanDefinition, beanName, args);
if (mergedBeanDefinition.isSingleton()) {
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);
}
// 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);
}
String scopeName = mergedBeanDefinition.getScope();
final Scope scope = (Scope) this.scopes.get(scopeName);
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
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);
}
}
}_M#]
이 부분을 크게 두 부분으로 나누어 볼 수 있겠습니다.
먼저 bean definiton을 찾는 부분(현재 factory에 없으면 부모 팩토리에서 찾는 부분)과 그 이후에 bean을 생성하는 부분입니다.
bean을 생성하는 부분은 다시 세 부분으로 나누어 볼 수 있겠습니다.
bean의 scope이 singleton 방식일 때 생성하는 부분 prototype일 때 생성하는 부분 그리고 그 이외의 scope일 때 bean을 생성하는 부분입니다.
bean difinition을 찾는 부분에서 결과물은 mergedBeanDefinition 변수 입니다. 이 변수를 만들기 위해 호출되는 getMergedBeanDefinition() 메소드를 살펴보겠습니다.
getMergedBeanDefinition() 메소드
[#M_ more.. | less.. |
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#]
checkMergedBeanDefinition() 메소드
[#M_ more.. | less.. |
protected void checkMergedBeanDefinition(RootBeanDefinition mergedBeanDefinition, String beanName, Object[] args)
throws BeansException {
// check if bean definition is not abstract
if (mergedBeanDefinition.isAbstract()) {
throw new BeanIsAbstractException(beanName);
}
// Check validity of the usage of the args parameter. This can
// only be used for prototypes constructed via a factory method.
if (args != null) {
if (mergedBeanDefinition.isSingleton()) {
throw new BeanDefinitionStoreException(
"Cannot specify arguments in the getBean() method when referring to a singleton bean definition");
}
else if (mergedBeanDefinition.getFactoryMethodName() == null) {
throw new BeanDefinitionStoreException(
"Can only specify arguments in the getBean() method in conjunction with a factory method");
}
}
}
_M#]
bean을 생성하는 부분에서 사용되는 getObjectForBeanInstance() 메소드를 살펴보겠습니다.
getObjectForBeanInstance()메소드
[#M_ more.. | less.. |
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#]
spring 2.0에서는 singleton과 prototype이 외에 session을 비롯한 세개의 scope이 더 추가 되었는데요 그러한 부분이 마지막 else문에서 다뤄지고 있습니다. 그런데 prototype이라는 단어가 들어가는 메소드를 호출하는 부분이 많이 보이고 있으며.. 왜 if (mergedBeanDefinition.isSession())과 같은 코드가 보이지 않을까요?
spring 2.0 referecnce에서 bean scope에 관한 부분입니다. 이 부분을 좀 더 살펴봐야겠습니다.