public Object getBean(String name) throws BeansException {
       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.
           

   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 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”);
           }
       }

   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);
}

}

}_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에 관한 부분입니다. 이 부분을 좀 더 살펴봐야겠습니다.