본문 바로가기

프로그래밍/Spring

전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-transaction.xml 변환)

지난 글에서는 ibatis, Mybatis를 연동하는 환경설정 파일인 context-sqlMap.xml, context-mapper.xml 파일을 Java Config 파일로 바꾸는 작업에 대해 설명하였다. 이번에는 이렇게 연동한 DB 관련 작업에 적용하는 트랜잭션 설정 파일인 context-transaction.xml을 Java Config 파일로 바꾸는 작업에 대해 설명하도록 하겠다. 

 

전자정부 프레임워크의 트랜잭션 방법은 XML에서 tx 스키마를 이용하는 AOP 방식으로 구현하고 있다. 이 얘기를 왜 하냐면 Spring에서 XML을 이용해서 트랜잭션을 설정하는 방법이 두 가지가 있어서 그렇다.

 

  • <tx:advice> 태그로 정의하는 어드바이스와 포인트컷을 이용하여 AOP로 구현하는 트랜잭션
  • <tx:annotation-driven /> 태그를 사용하여 @Transactional 어노테이션이 붙은 클래스, 메소드에 구현하는 트랜잭션

 

<tx:annotation-driven /> 태그를 사용해도 내부적으로는 Proxy 방식의 Spring AOP가 적용되기 때문에 두 방법 모두 AOP를 사용한다고 보면 된다(태클을 거실 분이 있을것 같아서 먼저 말하자면 <tx:annotation-driven /> 태그 속성 중 mode 라는 속성이 있다. 이 속성의 기본값이 proxy인데 이 속성이 proxy일 경우엔 Spring AOP를 사용한다. 그러나 이 속성이 aspectj로 설정되어 있으면 AspectJ를 이용하는 트랜잭션을 사용하게 된다) 

 

일단 이 정도의 선지식을 알아두고 현재 설정되어 있는 context-transaction.xml의 내용을 보도록 하자.

 

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">
	<tx:attributes>
		<tx:method name="*" rollback-for="Exception"/>
	</tx:attributes>
</tx:advice>

<aop:config>
	<aop:pointcut id="requiredTx" expression="execution(* egovframework.example.sample..impl.*Impl.*(..))"/>
	<aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx" />
</aop:config>

 

XML 내용을 보면 DataSource 기반의 TransactionManager인 DataSourceTransactionManager bean 을 선언한 뒤 이를 <tx:advice> 태그와 <aop:config> 태그들을 이용하여 트랜잭션을 구현하는 방식이다. 이 코드를 이해하는데는 별 문제가 없을 것 같고, 그럼 이와 같은 내용을 Java Config 방식으로 하는 방법에 대해 설명하도록 하겠다. DataSourceTransactionManager bean을 설정하는 <bean> 태그를 Java Config 방식으로 설정하는 방법은 최종 Java Config Source를 보여주는 것으로 하고 여기에서는 생략하겠다. 지금까지의 내용을 읽어왔으면 이 부분을 설정하는 것이 어렵지가 않기 때문이다. 

 

먼저 <tx:advice> 태그를 이용하여 어드바이스 정의하고 이를 활용하는 AOP 방식의 트랜잭션을 Java Config 방식으로 변환하는 방법이 없다. 그래서 이러한 방법이 아니라 다른 방법으로 트랜잭션을 구현하는 전환이 필요하다. 위에서 보면 <tx:advice> 태그를 사용하는 방법 말고 <tx:annotation-driven /> 태그를 사용하여 트랜잭션을 할 수 있다고 설명한 부분이 있다. 이 방법으로 트랜잭션을 구현한다고 생각하고 이를 Java Config 방식으로 변환하도록 하자.

(추가 글을 적어둔다. 이 부분에 대해 댓글로 알려주신 분이 있어서 내용을 살펴보니 설정이 가능하다는 판단이 서서 변환하는 방법이 없다..는 식의 단적인 결론 내린 것은 수정하고자 한다. 댓글로 알려주신 분이 비밀댓글로 달아주셔서 다른 사람들이 볼 수 없기에 댓글로 달아주신 분에게 비밀댓글을 풀어달라고 요청을 드린 상태다. 만약 풀어지지 않을 경우엔 댓글에 쓰여진 참조 링크를 글에 명시하도록 하겠다)

 

Spring에서는 Java Config 방식으로 트랜잭션을 구현할 수 있는데, 이를 위해 사용되는 어노테이션이 @EnableTransactionManagement 어노테이션이다. 이 어노테이션을 사용하면 <tx:annotation-driven /> 태그를 사용하는 것과 동일한 설정을 하게 된다. 다만 차이점이 존재하는 부분이 있다. <tx:annotation-driven /> 태그의 경우는 해당 태그에 적용되는 Transaction Manager bean을 찾는 방법을 bean의 이름으로 찾게 된다. <tx:annotation-driven /> 태그에는 속성으로 transactionManager란 속성이 있는데 이 속성을 이용해서 사용하고자 하는 Transaction Manager bean 이름을 설정하게 된다. 이 속성의 기본값은 transactionManager 로 되어 있어 Transaction Manager bean의 이름을 transactionManager로 설정하면 <tx:annotation-driven /> 태그에서 transactionManager 속성을 지정하지 않아도 이용이 가능하다. 그러나 @EnableTransactionManagement는 이러한 Transaction Manager bean을 찾는 방법을 bean의 타입으로 찾게 된다. Spring에서 제공하는 Transaction Manager 클래스들은 PlatformTransactionManager 인터페이스를 구현하고 있는데 @EnableTransactionManagement 어노테이션은 등록되어 있는 Spring Bean 들 중에서 PlatformTransactionManager 인터페이스를 구현한 클래스타입의 bean을 찾아서 이를 Transaction Manager로 사용하게 된다. 즉 bean의 이름을 구애받지 않기 때문에 Transaction Manager bean의 이름을 어떤것을 사용하든(txManager, tm 등) 상관이 없다.

 

그러면 이 설정을 사용하면 <tx:annotation-driven /> 과 동일한 기능의 설정을 한다는것은 이제 알았으니 이제 Sample 프로젝트를 고쳐야 한다. 어노테이션 기반으로 트랜잭션을 하기 때문에 Sample 프로젝트의 소스 중 트랜잭션 대상이 되는 부분에 @Transactional 어노테이션을 붙여야 한다. context-transaction.xml의 설정을 보면 트랜잭션의 대상이 되는 포인트것이 * egovframework.example.sample..impl.*Impl.*(..) 이러한 패턴에 속하는 메소드이기 때문에 현재 Sample 프로젝트에서 이 패턴의 대상이 되는 클래스와 메소드가 egovframework.example.sample.service.impl Package에 있는 EgovSampleServiceImpl 클래스에 있는 모든 메소드가 그 대상이 된다. 이 클래스의 메소드에 @Transactional 어노테이션을 붙인다. 아래에서 보여주는 코드는 메소드의 세부 코드는 생략했으나 이렇게 메소드레벨에 @Transactional을 선언해주어 @EnableTransactionManagement 어노테이션 설정으로 인한 트랜잭션 적용을 받도록 해주었다.

 

public class EgovSampleServiceImpl extends EgovAbstractServiceImpl implements EgovSampleService {

	@Transactional
	@Override
	public String insertSample(SampleVO vo) throws Exception {
		...
	}

	@Transactional
	@Override
	public void updateSample(SampleVO vo) throws Exception {
		...
	}

	@Transactional
	@Override
	public void deleteSample(SampleVO vo) throws Exception {
		...
	}

	@Transactional(readOnly=true)
	@Override
	public SampleVO selectSample(SampleVO vo) throws Exception {
		...
	}

	@Transactional(readOnly=true)
	@Override
	public List<?> selectSampleList(SampleDefaultVO searchVO) throws Exception {
		...
	}

	@Transactional(readOnly=true)
	@Override
	public int selectSampleListTotCnt(SampleDefaultVO searchVO) {
		...
	}
}

 

일단 Java Config 방식으로 트랜잭션 설정하는 방법은 이정도에서 마치고 한가지 부가적인 설명을 하고자 한다. 사실 @Transactional 어노테이션을 이용하는 트랜잭션 설정은 완전 범용적인 설정은 아니다. 이 방법은 트랜잭션을 적용해야 할 클래스 또는 메소드의 Source에 @Transactional 어노테이션을 붙여야 하기 때문에 프로그래머가 Source에 직접 접근이 가능할때 사용이 가능한 방법이다. 그러나 외부에서 배포된 클래스를 대상으로 트랜잭션을 적용해야 할 경우엔 이 방법을 사용할 수가 없다. 그래서 이러한 상황일 경우엔 XML을 사용하여 <tx:advice> 태그와 <aop:config> 태그를 이용하는 방법으로 접근해야 한다. 그러나 이렇게 할 경우엔 Java Config와 XML 설정 파일이 혼용이 되는 상황이 온다. 그래서 이럴 경우엔 XML 설정 파일을 Java Config에서 사용하는 의미로 @ImportResource를 이용하여 Java Config 설정 파일에서 XML 설정 파일을 이용한 설정 작업을 진행하는 것으로 작업하도록 한다.(비슷한 것으로 @Import 어노테이션이 있는데 이 어노테이션은 XML 설정 파일이 아닌 다른 Java Config 방식의 자바 클래스를 사용하는 것으로 환경 설정 작업을 진행한다고 생각하면 된다. 이 어노테이션은 차후에 설명하도록 하겠다)

 

@ImportResource("classpath:/egovframework/spring/context-transaction.xml")

 

마지막으로 context-sqlMap.xml 파일을 Java Config 방식으로 변경한 ContextSqlMap 클래스 소스와 context-mapper.xml 파일을 Java Config 방식으로 변경한 ContextMapper 클래스 소스를 보여주면서 이 글을 마무리하겠다.

 

package egovframework.example.config.root;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
// @ImportResource("classpath:/egovframework/spring/context-transaction.xml")
public class ContextTransaction {

	@Bean
	public DataSourceTransactionManager transactionManager(DataSource dataSource){
		DataSourceTransactionManager dstm = new DataSourceTransactionManager();
		dstm.setDataSource(dataSource);
		return dstm;
	}
	
}

 

 

목     차

 1. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(환경구축)

 2. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(기초)

 3. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-aspect.xml 변환)

 4. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-common.xml 변환)

 5. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-datasource.xml 변환)

 6. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-sqlMap.xml, context-mapper.xml 변환)

 7. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-transaction.xml 변환)

 8. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-idgen.xml, context-properties.xml, context-validator.xml 변환)

 9. 작성된 Java Config 클래스 파일들을 실제 등록해보자(RootContext 클래스 제작)

 10. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 1

 11. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 2

 12. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 3