Spring framework Controller에서는 일반적으로 동기 방식으로 서비스를 호출한다.
그러나 요청된 파라미터의 값에 따라 동시에 여러 서비스를 호출하여 결과를 받을 때 순차적으로 서비스를 호출하지 않고 비동기로 서비스를 호출하여 결과를 Return 받으면 서비스의 수행 성능을 향상 시킬 수 있다.
Controller에서 비동기적으로 서비스를 호출하기 위해서는 Java 1.5에서부터 지원하는 Future 기능을 사용하고, 응답을 받을 경우 호출되는 서비스에서 AsyncResult를 이용하여 결과를 Return할 수 있다.
Funcure 기능과 AsyncResult를 이용하기 위해서는 task관련 Bean을 다음과 같이 정의한다.
■ context-baen.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd"> <task:annotation-driven executor="taskExecutor"/> <!-- mvc:annotation-driven> <mvc:async-support default-timeout="2500" task-executor="taskExecutor"> <mvc:callable-interceptors> <bean class="org.springframework.web.servlet.config.MvcNamespaceTests.TestCallableProcessingInterceptor" /> </mvc:callable-interceptors> <mvc:deferred-result-interceptors> <bean class="org.springframework.web.servlet.config.MvcNamespaceTests.TestDeferredResultProcessingInterceptor" /> </mvc:deferred-result-interceptors> </mvc:async-support> </mvc:annotation-driven-->
<!-- Async Task --> <!-- task:annotation-driven scheduler="scheduler" executor="taskExecutor"/> <task:scheduler id="scheduler" pool-size="10"/-->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <property name="corePoolSize" value="100"/> <property name="maxPoolSize" value="100"/> <property name="queueCapacity" value="2000000000"/> <property name="keepAliveSeconds" value="120"/> </bean> </beans> |
비동기적으로 서비스를 호출하기 위해 <task:annotation-drive>을 설정하고, executor를 정의하여 Pool size와 Capacity를 정의한다.
다음은 비동기적으로 실행할 서비스를 생성한다.
■AsyncServiceImpl.java
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Service; @Service("asyncService") public class AsyncServiceImpl extends BaseService implements AsyncService{ @Async @Override public Future<List<Map<String, Object>>> selectUserListAsync(NexacroMapDTO dto) throws Exception { LOGGER.info("selectUserListAsync Start");
Map<String, Object> searchMap = getDataSet(dto, "searchMap"); Thread.sleep(2000); List<Map<String, Object>> resultList = getMapper("sbMapper").selectList("user.selUser", searchMap);
return new AsyncResult<List<Map<String, Object>>>(resultList); } @Async @Override public Future<List<Map<String, Object>>> selectUserListAsync1(NexacroMapDTO dto) throws Exception { LOGGER.info("selectUserListAsync1 Start"); Map<String, Object> searchMap = getDataSet(dto, "searchMap");
List<Map<String, Object>> resultList = getMapper("sbMapper").selectList("user.selUser", searchMap); LOGGER.info("selectUserListAsync1 End");
return new AsyncResult<List<Map<String, Object>>>(resultList); } } |
Service 메소드에 @Async Annotation을 설정하여 해당 메소드가 비동기적 수행을 정의한다.
@Async는 public 메소드에만 정의되고, 동일한 Class에서는 @Async 메소드를 호출할 수 없다. 즉 외부의 Class에서 @Async 메소드를 호출한다.
@Async로 정의된 메소드는 Return Type이 Future<?>이고 결과는 AsyncResult를 생성하여 결과를 Return한다.
다음은 서비스를 호출하는 Controller를 생성한다.
■AsyncController
@RequestMapping(value = "/sample/selectUserAsync.do") public ModelAndView selectUserAsync(NexacroMapDTO dto) throws Exception {
ModelAndView modelAndView = NexacroUtil.getModelAndView(dto); Future<List<Map<String,Object>>> future1 = asyncService.selectUserListAsync(dto); Future<List<Map<String,Object>>> future2 = asyncService.selectUserListAsync1(dto); // List<Map<String,Object>> resultList1 = future1.get(); // List<Map<String,Object>> resultList2 = future2.get(); modelAndView.addObject("list1", resultList1); modelAndView.addObject("list2", resultList2); return modelAndView; }
|
Controller에서 Future에 서비스의 Async Method를 호출한 후 결과를 받기 위해 생성된 future의 get Method를 호출하여 결과를 받는다.
■ 수행결과
INFO | createCompositeTransaction ( 300000 ): created new ROOT transaction with id 192.168.0.59.tm0000100063 INFO | createCompositeTransaction ( 300000 ): created new ROOT transaction with id 192.168.0.59.tm0000200063 INFO | selectUserListAsync1 Start INFO | selectUserListAsync Start INFO | AtomikosDataSoureBean 'xaSBDataSource': getConnection ( null )... INFO | AtomikosDataSoureBean 'xaSBDataSource': init... INFO | atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@1c182f16: calling getMetaData... INFO | 1. Connection opened INFO | 1. Connection.new Connection returned INFO | atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@1c182f16: calling getAutoCommit... INFO | 1. Connection.getAutoCommit() returned true INFO | addParticipant ( XAResourceTransaction: 3139322E3136382E302E35392E746D30303030313030303633:3139322E3136382E302E35392E746D31 ) for transaction 192.168.0.59.tm0000100063 INFO | XAResource.start ( 3139322E3136382E302E35392E746D30303030313030303633:3139322E3136382E302E35392E746D31 , XAResource.TMNOFLAGS ) on resource xaSBDataSource represented by XAResource instance oracle.jdbc.driver.T4CXAResource@5c7c0881 INFO | registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@48d3cd82 ) for transaction 192.168.0.59.tm0000100063 INFO | atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@1c182f16: calling prepareStatement(SELECT ID, NAME, PASSWORD, DESCRIPTION, USE_YN, REG_USER FROM TB_USER WHERE 1 = 1)... |
결과를 확인하면 로그에 selectUserListAsync1,과 selectUserListAsync 출력됨을 확인할 수 있으며, 각각의 서비스가 순차적으로 호출되지 않고 병렬로 호출되었음을 확인할 수 있다.
'Spring Framrwork' 카테고리의 다른 글
Spring framework RequestMapping을 XML 파일로 생성하기 (0) | 2018.07.17 |
---|---|
Spring framewok Redis session 관리 (0) | 2018.06.08 |
Mybatis ResultHandler를 이용한 ExcelDownload (3) | 2018.04.19 |
Spring framework Property Reload (0) | 2018.04.13 |
Mybatis include sql (0) | 2018.03.23 |