Google AdSense (text)

hidden logo stop

Moving

거지 같은 이글루스 광고노출 정책이 싫어서,
새 보금자리(http://blog.leocat.kr/)로 이사감.

[Spring] @Autowired와 <context:component-scan>, <context:annotation-config> Computer & Program

지금까지 <context:component-scan>에 대해 오해를 하고 있었다. <context:component-scan>은 @Component, @Repository, @Service, @Controller와 같은 녀석들을 annotation을 통해 bean을 생성할 수 있게 해주는 녀석으로 알고 있었다. 여태 잘못 알고 있었던게지.. 이 용도 외에 어마어마한 기능을 가지고 있는 녀석이었다.

오늘 겁나 신기한 상황에 처했는데.. @Autowired를 사용했는데 context를 로드해도 변수가 설정되지 않는 것이다. 다음 예제를 보면 잘 동작할 것 같은 냄새를 풍긴다.. 어디 하나 문제 없이 말이징.. (나만 그렇게 보이나?? -ㅅ-;;)

package test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main
{
    public static void main(String [] args)
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml");
        Foo foo = context.getBean("foo", Foo.class);
        foo.foo();
    }
}

class Foo
{
    @Autowired
    ApplicationContext context;
    
    public void foo()
    {
        Bar bar = this.context.getBean("bar", Bar.class);
        bar.bar();
    }
}

class Bar
{
    public void bar()
    {
        System.out.println("This is bar");
    }
}

root-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
    <bean id="foo" class="test.Foo" />
    <bean id="bar" class="test.Bar" />
</beans>


헌데 실제로 돌려보면 이런 예외를 만나게 된다. 아하하하하하하 분명히 24번째 줄에서 null이 될 가능성은 context뿐인데.. 이거 분명 @Autowired로 설정해 준 녀석인데 null이라니!! TㅅT

Exception in thread "main" java.lang.NullPointerException
    at test.Foo.foo(Main.java:24)
    at test.Main.main(Main.java:13)



별 삽질과 구글링을 시도하다가 우연히 <context:component-scan>을 사용했는데 동작하는 겻이다!! root-context.xml을 이렇게 수정해 보자.

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <context:component-scan base-package="test" />
    <!-- 용도에 따라 위 또는 아래를 선택!! -->
    <context:annotation-config />

    
    <bean id="foo" class="test.Foo" />
    <bean id="bar" class="test.Bar" />
</beans>


그리고는 거꾸로 원인을 찾기 시작했다. 답은 정말 가볍게 나왔다. Spring API에서 Autowired를 찾아보니 실제 injection은 BeanPostProcessor를 통해서 수행된다고 쓰여 있다. 그리고 Autowired를 수행하는 BeanPostProcessor인 AutowiredAnnotationBeanPostProcessor을 참고하라는 문구가 쓰여 있다. 따라가 보니 NOTE라고 쓰여 있는 것이 아닌가!!

Note: A default AutowiredAnnotationBeanPostProcessor will be registered by the "context:annotation-config" and "context:component-scan" XML tags. Remove or turn off the default annotation configuration there if you intend to specify a custom AutowiredAnnotationBeanPostProcessor bean definition.


그리고 이런 내용도 있다. annotation을 통한 injection은 XML로 설정되는 것 보다 먼저 수행된다. 때문에 XML로 injection이 되면 덮어 씌여질 수 있다. 이거 깜빡하고 중복해서 쓰면 큰일 날 수도 있겠다. annotation을 쓸건지 XML에서 설정할건지 룰을 정해서 써야겠다.

NOTE: Annotation injection will be performed before XML injection; thus the latter configuration will override the former for properties wired through both approaches.


오늘의 교훈..
API 문서를 꼼꼼히 살펴보자.. 그리고 Javadoc으로 API 문서 안 쓰는 놈들!! 이렇게라도 답을 챁을 수 있게 꼭 써놓기를!! 안 그러면 코드 뒤져야 한다 TㅅT


+ 참고 사이트 : Spring Autowiring & Component Scanning Problems - Part 3: Autowiring

덧글

  • aldehyde7 2011/11/10 17:01 # 삭제 답글

    오잉 형님 요즘 스프링하시나봐요?
  • Sigel 2011/11/10 17:02 #

    자바하는데.. 스프링은 필수징~
  • 반키치 2015/05/24 21:16 # 삭제 답글

    오 좋은지식 알고 갑니당..^^
댓글 입력 영역

Google AdSense (text/image)