Whiteship's Note


[스프링 3.0] @Async 테스트

Spring/3.0 : 2010.03.04 17:55


@Async 애노테이션을 사용한 메서드의 반환 타입은 둘 중 하나여야 합니다. void 거나.. java.util.concurrent.Future 타입이어야 한다네요. 뭐.. 그러니까 사실상 하나나 마찬가지이죠. 그렇다고 해서 다른 리턴타입으로 설정하면 비동기로 동작하지 않는 건 아닙니다. 다만;; 해당 메서드의 클라이언트 입장에서 보면 리턴값이 전부 null 이기 때문에 황당한 경우가 발생할테지만 말이죠.

스프링에서 Future 인터페이스의 구현체로 AsyncResult를 제공해줍니다. 이걸 이용해서 간단하게 Thread를 반환하는 비동기 메서드를 만들었습니다.

    @Async
    public Future<Thread> more() {
        return new AsyncResult<Thread>(Thread.currentThread());
    }

@Async는 @Transaction과 비슷하게 타입에 선언할 수도 있습니다. 그러면 해당 클래스의 모든 메서드가 비동기 메서드로 처리되겠죠.

<task:executor id="myExecutor" pool-size="5"/>

쓰레드 풀 갯수를 5개로 설정해 놓고 다음과 같이 테스트를 해봤습니다.

    @Test
    public void async() throws Exception {
        assertThat(beanService, is(notNullValue()));
        Set<Thread> threads = new HashSet<Thread>();

        for(int i = 0 ; i < 200 ; i++){
            collectThreadInfo(beanService.more(), threads);
        }
        assertThat(threads.size(), is(5));
        assertThat(threads.contains(beanService.more().get()), is(true));
    }

    private void collectThreadInfo(Future<Thread> future, Set<Thread> threads) throws Exception {
        threads.add(future.get());
    }

200번까지 안돌려도 상관없지만. 그냥.. 충분히 돌려서 쓰레드 풀에 있는 모든 쓰레드를 컬렉션에 모아둔 다음에 쓰레드 풀에서 만든 쓰레드 갯수를 확인하고 마지막으로 한 번 더 호출해서 반환 받은 Thread가 현재까지 사용한 쓰레드 중 하나인지 확인합니다.


top

TAG @Async, Spring

[스프링 3.0] @Async 사용하기

Spring/3.0 : 2009.12.10 13:59


참조: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch25s05.html#scheduling-annotation-support-async

봄싹 사이트에서 스터디 개설/변경, 모임 개설/변경 시에 알림 서비스로 이메일, 구글 메신저, 트위터로 알림 메시지를 전송합니다. 그런데, 사용자가 많아지다보니 해당 작업을 완료하는데 걸리는 시간이 너무 길어졌습니다. 불편해졌죠. 사실 관리자 권한이 있는 사람들만 만드는거라, 스터디 참여자 입장에서는 그런 불편을 알 수가 없을테지만, 저희는 내부적으로 좀 불편해 하고 있었습니다.

그러던 중 보게 된 것이 바로 @Async.. 딱 원하던 기능입니다.

필요한 빈 설정은

    <!-- ============================================================= -->
    <!--  Spring 3.0 @Task @Async                                      -->
    <!-- ============================================================= -->
    <task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>

    <task:executor id="myExecutor" />

    <task:scheduler id="myScheduler" />

적용하려면, 원래 작업을 별도의 클래스로 빼내고 그것을 참조하도록 수정하는 것이 좋겠습니다. 안그럼 동작하질 않더라구요,

@Service
public class BeanService {

    public void normal(){
        System.out.println("===========================");
        System.out.println(Thread.currentThread());
        System.out.println("===========================");
        System.out.println("do it");
        this.more();
    }

    @Async
    public void more() {
        System.out.println("===========================");
        System.out.println(Thread.currentThread());
        System.out.println("===========================");
        System.out.println("more");
    }

}

예를 들어, 위와 같은 경우 normal() 내부에서 more()를 호출할 경우에는 @Async가 적용되지 않습니다.
more()를 직접 호출할 떄는 적용됩니다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class AsyncAnnoTest {

    @Autowired BeanService beanService;

    @Test
    public void async(){
        assertThat(beanService, is(notNullValue()));
        beanService.normal();
        beanService.more();
    }

}

대충 만든 테스트로 돌려보면 다음과 같은 결과를 볼 수 있습니다.





top

TAG @Async