습관이 사람을 만든다.

화가 날 땐 한 탬포 쉬기.

오늘도 ITA/EA 학술회를 가는 도중에 좁은 인도에서 차를 빼고 있는 사람 때문에 갑자기 다른 사람들과 부딪힐뻔 했다.  또 사람들이 차때문에 막혀있는 그곳을 향해 차머리를 돌리는 거였다.(이제 생각해 보니..그쪽이 차가 빠져나가는 길이였나보다..)놔서 이러는 건지 갑자기 화가 팍.. 치밀었고.. “아 씨X 왜 인도에서 차를 몰고 지X이야”가 순식간에 입밖으로 나왔다. 운전자는 나보다 나이도 많아 보였다. 거기에 나랑 같이 차에 밀리던 다른 아주머니까지 나와 거의 동시에 욕을 하셨다.
그렇게 5초가 지나고.. ‘아.. 젠장.. 어제 한 탬포 쉬기를 배웠는데.. 역시 잘 안되네’ 라는 생각이 들었다. 기선아. 그러지 말자. 참을 수 있었자나.

잘못을 밖으로 돌리지마 다 너 자신이 선택한 일이야.

어젯밤 회장을 그만 두겠다는 내용의 글을 과홈에 올리고야 말았다. 드디어 결심을 실행에 옮겼다. 그리고 예상했던 일이 발생했다. 어느 선배님께서 그러한 내 모습에 실망하셨다는 내용의 글을 올리셨고 궁금한것이 있다며 물어오셨다. 1. 처음에 회장을 왜 하게 되었는가? 2. 회장으로써 맡은 역할은 잘했나? 3. 학부생들 소속감을 위해 무슨일을 했나? 4. 후회하는가? 이 네가지 질문이였다. 거기에 나의 답변 1은 01학번이 해야한다는 외부 압박과 아무도 하지 않겠다는 동기들 사이에서 그냥 내가 하겠다고 했다는 답변을 했다. 어리석었다 백기선.. 인생은 나의 것인데 왜 외부 요인에 의해 선택을 했다는 변명을 했을까..그러고 싶었나. 2번에 대한 답변은 “회장으로써의 역할”이라는 의미가 자의적이기 때문에 그 형이 원하는 대답을 들을 수 없었을 것이다. 3번에 대한 답변은 그 형이 생각하고 있는 “소속감”이라는 것이 무엇인지 모르겠기에.. 내가 생각하는 소속감이란 파씨즘 따위가 아닌 그냥 좋은 과를 만드는 것이라 대답했고 몇몇 학우들에게는 제대로 전달이 됐다고 생각한다고 했다. 4번은 이룬것도 있고 못이룬것도 있기에 후회한다 안한다로 단순하게 말할수가 없다고 말을 했다. 사실 이런 것들이 회장을 그만 두게하는 역치를 넘는 힘을 가지고 있진 않다. 역치를 넘어버린건 내 스스로의 나약함과 변덕 때문이지 외부 요인 때문이 아닌데.. 자꾸 외부 요인 탓을 하고 있는 기선아. 조금 비겁해 보인다.

모든 일을 Agile-ly 하자!

오늘 정리한 ‘BeanFactory를 구현한 메소드 살펴보기’를 적고나니 뭔가 한결 가벼운 기분이 든다. 그전에는 메소드 하나하나를 뜯어보느라 시간도 많이 걸리고 한번에 정리가 안되기 때문에 그 중압감 때문에 점점 하기 싫어짐을 느꼈다. 하지만 오늘 매우 단순하고 나만을 위한 정리를 해버렸다. 그러고 나니 어느 부분을 더 보충을 해야 할지 어느부분은 이정도면 될지 그러한 전체적인 구조가 들어오기 시작했다. 이제 슬슬 보충하고 수정해 나가면 되겠다는 생각이 드니깐 뭔가 한듯하다. 일단 기분이 한결 상쾌하다면 그걸로 된거 아니겠는가 생각한다. agile 하면 좋은 점은 또하나.. 피드백을 빨리 받을 수 있다는 것이다. 이것은 굉장한 장점이 된다. 협업의 장점을 살리는데도 역시 빨리 뭔가를 만들어서 팀원과 공유를 하는 것이 가장 agile한 방법인듯하다. 기선아 Agile-ly 하자.

BeanFactory를 구현한 메소드 살펴보기

먼저 BeanFactory에 있는 인터페이스를 지난번 글에 살펴보았습니다.

BeanFactory 인터페이스에 있는 책임(메소드)들을 구현 해 놓은 클래스는 AbstractBeanFactory 클래스 입니다.

이 클래스에서 구현한 public boolean containsBean(String name) 메소드안에서 호출되는 메소드를 보겠습니다.

자기 자신 factory 안에서 찾을 경우 입니다.

  1. containsLocalBean(name)
    1. transformedBeanName(String name)
    2. return containsSingleton(beanName) or containsBeanDefinition(beanName)
  2. return ture

자기 자신의 factory 안에서 찾지 못할 경우 입니다.(1-2.의 return값이 false일때)

  1. containsLocalBean(name)
  2. getParentBeanFactory()
  3. return parentBeanFactory.containsBean(originalBeanName(name))
    1. transformedBeanName(name)


public String[] getAliases(String name) 메소드
를 보겠습니다.

  1. transformedBeanName(name)
  2. new ArrayList()
  3. name.startsWith(FACTORY_BEAN_PREFIX)
  4. aliases.add(fullBeanName) -> fullBeanName 이 name과 같지 않을 때만 호출 됨
  5. this.aliasMap.entrySet().iterator() -> 루프를 돌기 위한 이터레이터 가져오기
  6. (Map.Entry) it.next()
  7. entry.getKey()
  8. aliases.add(key) -> key가 name하고 같지 않을 때만 호출 됨
  9. !containsSingleton(beanName) && !containsBeanDefinition(beanName)
  10. getParentBeanFactory()
  11. aliases.addAll(Arrays.asList(parentBeanFactory.getAliases(fullBeanName)))
  12. return StringUtils.toStringArray(aliases)

public Object getBean(String name) throws BeansException 메소드
public Object getBean(String name, Class requiredType) throws BeansException 메소드를 같이 보겠습니다.

  • return getBean(name, null, null); -> getBean(String)
  • return getBean(name, requiredType, null); -> getBean(String, Class)

그래서 public Object getBean(String name, Class requiredType, final Object[] args) throws BeansException 메소드를 보겠습니다.

  1. public Object getBean(String name, Class requiredType, final Object[] args) throws BeansException
    1. transformedBeanName(name)
    2. getSingleton(beanName)
      1. this.singletonCache.get(beanName)
    3. 위 2번에서 호출한 메소드로부터 반환된 값이 null 이 아니면
    4. isSingletonCurrentlyInCreation(beanName)
    5. logger.isDebugEnabled()
    6. logger.debug(“~~~~~”);
    7. containsBeanDefinition(beanName)
    8. 위 7번에서 호출한 메소드로부터 반환된 값이 true면
    9. getMergedBeanDefinition(beanName, false)
    10. getObjectForBeanInstance(sharedInstance, name, mergedBeanDefinition)
    11. 위 7번에서 호출한 메소드로부터 반환된 값이 false면
    12. getObjectForBeanInstance(sharedInstance, name, null)
    13. required Type이 있을 경우 그 타입과 얻어진 객체와의 타입을 비교하고 같지 않으면
    14. throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass())
    15. 13번에 걸리지 않으면
    16. return bean

위의 경우는 싱글톤 케시로 부터 빈을 가져오는 제일 간단한 경우였습니다. 그렇치 않은 경우는 매우 복잡하기에 다음에 알아보겠습니다.

public boolean isSingleton(String name) throws NoSuchBeanDefinitionException 메소드
를 보겠습니다.

  1. transformedBeanName(name)
  2. getSingleton(beanName) -> 반환 값을 beanInstance 변수에 대입.
  3. 위 2번에서 호출한 메소드로부터 반환된 값(beanInstance)이 null 이 아니면
  4. name이 FactoryDerefedence는 아니고 beanInstance가 FactoryBean이면
  5. BeanFactoryUtils.isFactoryDereference(name)
  6. return ((FactoryBean) beanInstance).isSingleton()
  7. 위 4번 조건에 해당하지 않으면
  8. return true

위의 경우는 싱글톤 객체를 찾았을 때의 제일 간단한 경우였습니다. 그렇치 않은 경우는상위 팩토리를 찾게 됩니다.

public Class getType(String name) throws NoSuchBeanDefinitionException 메소드를 보겠습니다.

  1. transformedBeanName(name)
  2. getSingleton(beanName)
  3. 위 2번에서 호출한 메소드로부터 반환된 값(beanInstance)이 null 이 아니면
  4. name이 FactoryDerefedence는 아니고 beanInstance가 FactoryBean이면
  5. return ((FactoryBean) beanInstance).getObjectType()
  6. 위 4번 조건에 해당하지 않으면
  7. return beanInstance.getClass()

위의 경우는 싱글톤 객체를 찾았을 때의 제일 간단한 경우였습니다. 그렇치 않은 경우는상위 팩토리를 찾게 됩니다.

몸이 아프면

집중이 안되서 힘들다.

공부도 할 수가 없고 놀 수도 없다.

오늘 들었는데 몸이 아프다는 건 몸이 자기한테도 관심좀 가져 달라는 목소리라고 한다.

그럴듯 하다고 생각했다.

감기가 심하게 걸릴때면 항상 “내가 내 자신에게 너무 소홀했구나” 라고 생각하곤 했다.

오늘 약간 몸이 안좋기 때문에 할 일은 많지만 일찍 자야겠다. 🙂

절대!! 핑계가 아니라..그냥 내 자신이 내게 관심을 가져 달라고 하고 있다. ㅋㅋㅋㅋ

 

생강 귤차 맛있겠다.

Object getBean(String name) 메소드 구현 살펴보기-중간 부분

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