2012-08-29 4 views
3

우리는 응용 프로그램의 멀티 스레드 부분과 데이터베이스 액세스 사이에 일종의 보증을 구현하여 DB가 너무 많은 스레드 (사용자 요구 사항) 동시에 시스템의 다른 부분을 필요한만큼의 스레드와 함께 사용합니다.ThreadPoolTaskExecutor 테스트 중에 스프링 컨텍스트가 살아 있는지 확인하는 좋은 방법

디자인은 (스프링 배치 파티셔닝 + ThreadPoolTaskExecutor를 사용한 데이터 액세스 처리) 작동하지만 디자인을 테스트하는 데 문제가있는 것 같습니다 (http://helenaedelson.com/?p=432 기준).

지금은 Threadsleep (4000)을 내 단위 테스트에 추가하여 생성 된 추가 스레드가 작업을 끝내기 전에 Spring 컨텍스트가 테스트에서 강제 종료되지 않도록해야합니다. 리턴 값을 메인 쓰레드에 돌려 준다.

누구든지이 테스트를보다 스마트하게 구현하는 방법에 대해 더 좋은 아이디어가 있습니까?

테스터 :

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration({ "classpath:partitionJdbcJob.xml" }) 
@DirtiesContext(classMode = ClassMode.AFTER_CLASS) 
public class TaskTests { 
protected static final Logger logger = LoggerFactory.getLogger(TaskTests.class); 

@Autowired 
private OrderServiceImpl orderService; 

@Test 
public void testExecution() { 
    logger.info("Starting execution thread..."); 

    for (int i = 0; i < 8; i++) { 
     orderService.dispatch(); 
    } 

    try { 
     // So that spring context is not destroyed from under the multi-threaded runnables 
     Thread.sleep(4000); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 

}

시험 서비스 :

@Service("orderServiceImpl") 
public class OrderServiceImpl { 
protected static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class); 

@Resource(name = "beanTaskExecutor") 
private TaskExecutor taskExecutor; 
// private AsyncTaskExecutor taskExecutor; 

CompletionService completionService; 

@Autowired 
public void OrderServiceImpl(DataSource dataSource) { 
    completionService = new ExecutorCompletionService(taskExecutor); 
} 

public void dispatch(final RetailPriceOptimization order) { 
    logger.info("Starting dispatch execution..."); 

    if (this.taskExecutor != null) { 
     logger.info("taskExecutor found..."); 
     this.taskExecutor.execute(new Runnable() { 
      public void run() { 
       withExecutor(order); 
      } 
     }); 
    } 

    try { 
     Object future1 = completionService.take().get(); 
     Object future2 = completionService.take().get(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } catch (ExecutionException e) { 
     e.printStackTrace(); 
    } 
    logger.info("Completed dispatch execution..."); 
} 

private void withExecutor(final RetailPriceOptimization order) { 
    logger.info("Starting withExecutor execution..."); 

    Object result1 = completionService.submit(new Callable<String>() { 
     public String call() { 
      return findById("0000dd2gsl1u1546"); 
     } 
    }); 
    Object result2 = completionService.submit(new Callable() { 
     public Object call() { 
      return orderDao.find(new Long("16")); 
     } 
    }); 
} 

}

답변

0

은 현재 테스트 당신이 completionService .take()를 호출하기 때문에 동기 것 같다 두 배의 내부 dispatch(...) 방법. take()은 작업이 완료 될 때까지 대기합니다. 그래서 내가 읽었을 때, 당신은 쓰레드가 전혀 필요 없다.

또한 CompletionService에 대한 필요성을 전혀 알지 못합니다. 2 가지 선물을 유지 한 다음 한 번에 하나씩 get(...)으로 전화하십시오. 어쨌든 2 통화가 끝나기를 기다리고있는 것처럼 보이고 동시에 통화가 실행됩니다. CompletionService은 결과 중 하나에서 즉시 작업을 시작할 수있는 경우에만 유용합니다.

0

서비스를 조금 리팩터링하려고하지 마십시오. 당신이 새로운 방법이 당신이 응답하거나 사용하는 단지 하나를 병합하는 데 사용하는 방법, 그것은 비동기를 실행하기 위해선, @Async에 따라 병렬 사용 실행하려는 모든 프로세스에 대한

@Service 
public class ConcurrentService{ 

    public Map<String, Object> createList(){ 
     this.asynCall(); 
    } 

    @Async("taskExecutor") 
    private Future<Map<String, Object>> asynCall(){ 
      //I will use submit instead of execute 
      return this.taskExecutor.submit(new Callable(){ 
       //Override the proper logic following interface 
      }) 
    ..... 
    } 

} 

병렬 프로세스를 시작하고, Future API를 사용하여 작업이 완료 될 때까지 대기하십시오.

부울 isDone()이 작업이 완료되면 true를 반환합니다. 완료는 일 수 있습니다.이 경우 모두 에서 정상 종료, 예외 또는 취소로 인해이 메서드는 true를 반환합니다. 모든 선물이

while(future1.isDone() future2.isDone()){ 
//Do Something in the meanwhile 
} 
//Code will start the execution once both process are completed 

당신은 더 쉽고 동적으로 completition 기다릴 확인하기 위해 포장 방법을 구축 할 수 있습니다 완료 될 때까지

이 대기 할 것입니다.이것이 당신이 테스트가 모든 비즈니스 로직 제대로 실행에 위의 설정이됩니다, 실제 객체와 서비스를 사용하는 등 통합 테스트입니다 나 또한

<task:annotation-driven executor="taskExecutor" mode="aspectj" /> 

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> 
    <property name="corePoolSize" value="50" /> 
    <property name="maxPoolSize" value="300" /> 
    <property name="queueCapacity" value="30" /> 
</bean> 

및 : 그 작업을 수행하는

봄 설정입니다 모든 프로세스가 완료 될 때까지 당신이 늘 Thread.sleep를이 필요 귀하의 예에서 메소드 실행 후, 대기>

orderService.dispatch(); 

당신은 과정이 확인 어설 션의 목록을 만들 수 있습니다 예상대로 작동, 이것을 잊지 마라. 테스트 목적의 일부.

관련 문제