2007/07/17 09:16 Developer
spring annotation @Required의 효용성
우리는 spring을 사용을하다가 보면, 실수를 할때가 있다.
나는 같은 인터페이스를 구현한 여러 클래스를 하나의 클래스에 등록을 해서 순차적으로 실행을 하는 프로그램을 만들었다.
특정 기능에서 후처리하는 것을 같은 인터페이스를 구현해서 일괄적인 처리를 하는 것과 동시에 어떤 일을 하는지 명확히 알수가 있어서 좋았다. 여러가지 작업들이 있었지만, 모두 런타임시에 에러가 발생을 하면 무시를 하고 넘어가야 할 작업들이었다.
버그의 원인으로 의심을 한것
1. 외부서비스와 연동을 통해서 값을 얻어오는데, 연결이 잘 안되거나, timeout이 발생한다.
2. 데이터를 DTO로 populate를 하는데, null인 값을 호출을 한다.
3. spring configuration이 문제가 있다.
사실 3번을 로그를 확인하다가 가장 나중에 알아냈다. 같은 작업을 2번을 등록했지만, 뒤에 실행되는 것 하나는 런타임에 에러가 나서 이클립스 디버깅 모드로 돌려도 한번 밖에 실행이 되지 않을 것이었다. 물론, 예외처리를 무시하게 했던 글로벌 에러처리를 제거했으면 빠른 시간에 해결이 되었겠지만, 너무 많은 로그들이 나오고 있어서 눈으로 학인하기가 쉽지 않은 상태였다.
같은 인터페스의 구현체를 2번이나 등록을 하는 실수를 범했다. 내가 눈으로 확인했을 당시에는 등록하는 클래스의 ref에는 이름이 중복된게 없었다.
아래와 같이 한 것이다. 똑같은 구현체를 다른 이름으로 2번을 등록했다.
물론, 처음부터 잘 등록을 하면 되었으나, 간혹 C&P를 하다가 실수를 할수도 있고, configuration이 길어지게 되면, 눈으로 보는 것도 집중력이 떨어진다. (사람의 눈을 얼만큼 믿어야 할까?)
spring context가 올라갈때 에러가 발생을 하지 않으니 configuraiton에 의심도 하지 않았다.
계속된 NullPointerException이 나와도 과거에 외부 서비스가 연동이 안되면 Null이 떨어진 경험이 나를 더욱더 잘못된 곳에서 디버깅을 하게 만들었다. 한정된 경험은 시야를 무척이나 좁게 만든다.
같이 디버깅을 하던 자바지기가 하나의 메일을 주었다. 이것은 그 동안에 묵혔던 버그를 해결하게 충분한 기능이었다. 나에게는 운이 좋았다...^^
아래 내용으로 해결이 어려울 수도 있지만, spring context에 의도하지않은 객체 생성에 대해서 그리고, 의도한 dependency를 위해서 유용한 방법이다.
내용은 다음과 같다.
http://www.springframework.org/docs/reference/metadata.html
http://www.springframework.org/docs/api/org/springframework/beans/factory/annotation/Required.html
정리를 해보면, 아래와 같이 설정을 하면된다.
1. required사용을 위해서 빈을 등록한다.
2. 사용할 빈을 등록한다.
3. 코드상에 setter에 @Required을 넣어준다.
4. 제대로 DI가 되지 않으면 context 로딩시 다음과 같이 예외를 발생한다.
좀더 optional한 사용법은 여기를 참조
http://younghoe.info/trackback/504
나는 같은 인터페이스를 구현한 여러 클래스를 하나의 클래스에 등록을 해서 순차적으로 실행을 하는 프로그램을 만들었다.
특정 기능에서 후처리하는 것을 같은 인터페이스를 구현해서 일괄적인 처리를 하는 것과 동시에 어떤 일을 하는지 명확히 알수가 있어서 좋았다. 여러가지 작업들이 있었지만, 모두 런타임시에 에러가 발생을 하면 무시를 하고 넘어가야 할 작업들이었다.
버그의 원인으로 의심을 한것
1. 외부서비스와 연동을 통해서 값을 얻어오는데, 연결이 잘 안되거나, timeout이 발생한다.
2. 데이터를 DTO로 populate를 하는데, null인 값을 호출을 한다.
3. spring configuration이 문제가 있다.
사실 3번을 로그를 확인하다가 가장 나중에 알아냈다. 같은 작업을 2번을 등록했지만, 뒤에 실행되는 것 하나는 런타임에 에러가 나서 이클립스 디버깅 모드로 돌려도 한번 밖에 실행이 되지 않을 것이었다. 물론, 예외처리를 무시하게 했던 글로벌 에러처리를 제거했으면 빠른 시간에 해결이 되었겠지만, 너무 많은 로그들이 나오고 있어서 눈으로 학인하기가 쉽지 않은 상태였다.
같은 인터페스의 구현체를 2번이나 등록을 하는 실수를 범했다. 내가 눈으로 확인했을 당시에는 등록하는 클래스의 ref에는 이름이 중복된게 없었다.
아래와 같이 한 것이다. 똑같은 구현체를 다른 이름으로 2번을 등록했다.
<bean id="movieLister1" class="x.y.SimpleMovieLister" />
<bean id="movieLister2" class="x.y.SimpleMovieLister" />
<bean id="tasksAfter" class="x.y.TasksAfter" >
<property name="afterTasks">
<list>
<ref bean="movieLister1" />
<ref bean="movieLister2" />
</list>
</property>
</bean>
<bean id="movieListerMain" class="x.y.SimpleMovieListerMain">
<property name="tasksAfter" ref="tasksAfter" />
</bean>
<bean id="movieLister2" class="x.y.SimpleMovieLister" />
<bean id="tasksAfter" class="x.y.TasksAfter" >
<property name="afterTasks">
<list>
<ref bean="movieLister1" />
<ref bean="movieLister2" />
</list>
</property>
</bean>
<bean id="movieListerMain" class="x.y.SimpleMovieListerMain">
<property name="tasksAfter" ref="tasksAfter" />
</bean>
물론, 처음부터 잘 등록을 하면 되었으나, 간혹 C&P를 하다가 실수를 할수도 있고, configuration이 길어지게 되면, 눈으로 보는 것도 집중력이 떨어진다. (사람의 눈을 얼만큼 믿어야 할까?)
spring context가 올라갈때 에러가 발생을 하지 않으니 configuraiton에 의심도 하지 않았다.
계속된 NullPointerException이 나와도 과거에 외부 서비스가 연동이 안되면 Null이 떨어진 경험이 나를 더욱더 잘못된 곳에서 디버깅을 하게 만들었다. 한정된 경험은 시야를 무척이나 좁게 만든다.
같이 디버깅을 하던 자바지기가 하나의 메일을 주었다. 이것은 그 동안에 묵혔던 버그를 해결하게 충분한 기능이었다. 나에게는 운이 좋았다...^^
아래 내용으로 해결이 어려울 수도 있지만, spring context에 의도하지않은 객체 생성에 대해서 그리고, 의도한 dependency를 위해서 유용한 방법이다.
내용은 다음과 같다.
http://www.springframework.org/docs/reference/metadata.html
http://www.springframework.org/docs/api/org/springframework/beans/factory/annotation/Required.html
정리를 해보면, 아래와 같이 설정을 하면된다.
1. required사용을 위해서 빈을 등록한다.
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
2. 사용할 빈을 등록한다.
<bean id="movieLister" class="x.y.SimpleMovieLister">
<!-- whoops, no MovieFinder is set (and this property is @Required) -->
</bean>
<!-- whoops, no MovieFinder is set (and this property is @Required) -->
</bean>
3. 코드상에 setter에 @Required을 넣어준다.
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can 'inject' a MovieFinder
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually 'uses' the injected MovieFinder is omitted...
}
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can 'inject' a MovieFinder
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually 'uses' the injected MovieFinder is omitted...
}
4. 제대로 DI가 되지 않으면 context 로딩시 다음과 같이 예외를 발생한다.
Exception in thread "main" java.lang.IllegalArgumentException:
Property 'movieFinder' is required for bean 'movieLister'.
Property 'movieFinder' is required for bean 'movieLister'.
좀더 optional한 사용법은 여기를 참조
http://younghoe.info/trackback/504