이전 시간에는 Mybatis가 무엇인지, Mybatis의 구성요소는 무엇이 있는지에 대해 알아보았다.
앞으로는 현재 업무환경에서 사용하고 있는 Spring Boot + Batch(executor-type)에 대한 내용을 다루려고 한다.
먼저 이번 시간에는 Spring Boot에 대해 공부해보았다.
Spring Boot가 Spring에 비해 가지는 장점은 많다. 하지만 라이브러리를 접근하는 측면이라면 가장 뚜렷한 장점으로 AutoConfiguration
을 고를 수 있을 것이라고 생각한다.
AutoConfiguration: 생성하고 싶은 Bean들을 Configuration으로 지정해두어 자동으로 구성해주는 Spring Boot의 기능
AutoConfiguration으로 빈을 구성하므로서, 우리는 이전 포스팅에서 다루었던 Mybatis 구성요소들의 생명주기를 신경 쓸 필요 없이 Mybatis를 사용할 수 있게 된다.
org.mybatis.spring.boot.autoconfigure
를 확인해보자.
해당 패키지에는 Mybatis의 AutoConfiguration을 위한 클래스들이 정의되어있다. 특히 MybatisAutoConfigration.class
를 보면 어떤 Bean들이 Configuration되어 Bean으로 구성되는지 알 수 있다.
먼저 클래스명을 봐보자. 해당 클래스는 Configuration이므로 Spring Boot의 특성상 어노테이션만 확인해도 많은 정보를 얻을 수 있다.
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {
위의 코드를 보면 다음의 사항들을 알 수 있다.
MybatisProperties.class
에 ConfigurationProperties 방식으로 설정값을 받는다SqlSessionFactory.class
, SqlSessionFactoryBean.class
, DataSource.class
와 같은 Bean들을 조건부로 등록한다. DataSourceAutoConfiguration.class
, MybatisLanguageDriverAutoConfiguration.class
의 Configuration 등록이 끝난 후 해당 Configuration을 등록한다.다만, 실제로 Configuration을 통해 등록되는 Bean이 어떤 것들이 있는지는 코드를 봐야 자세히 알 수 있다.
예로 간단하게 정의되어있는 SqlSessionTemplate
을 확인해보자.
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
if (executorType != null) {
return new SqlSessionTemplate(sqlSessionFactory, executorType);
} else {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
해당 설정은 SqlSessionTemplate이 Bean으로 등록되지 않는 경우 활성화 되며(@ConditionalOnMissingBean
) 앞서 언급한 MybatisProperties.class
의 값에 따라 분기된다.
즉, 라이브러리의 사용자의 선택에 따라 Bean의 생성자가 선택되게 된다. executorType을 ExecutorType.BATCH
와 같이 설정한 경우는 생성자의 파라미터로 들어가게 되며, null인 경우 사용하지 않는 간단한 분기이다.
이와 같은 방식으로 기존에는 개발자가 생성하고 생명주기를 관리해야했던 SqlSessionFactory
, SqlSession
등의 Mybatis 구성요소를 Spring Boot에서는 AutoConfiguration으로 생성하고 관리를 해준다.
이에 따라 개발자는 라이브러리를 사용하기 위한 구성요소의 생명주기를 신경쓰지 않고 원하는 기능을 사용하는 편의를 누릴 수 있게 된다.
Spring이 제공하는 또 하나의 이점은 transaction management이다.
transaction을 개발자가 필요할 때마다 구현하려면 어떻게 해야할까?? 아마 다음과 같이 구현을 해야 할 것이다.
// 1. 커넥션 가져오기
Connection connection = dataSource.getConnection
try (connection) {
// 2. AutoCommit 설정 해제
connection.setAutoCommit(false);
// 3. statement 실행
// 4. transaction commit
connection.commit();
} catch (SQLException e) {
// 5. 롤백 처리
connection.rollback();
}
개발자가 transaction을 개발 할 경우 크게 위와 같이 다섯개의 단계로 구현을 할 수 있다.
true
로 설정하면 매 statement 마다 개별의 transaction을 가진다고도 볼 수 있다. 위의 구현을 보면 알 수 있듯이 하나의 connection에서는 AutoCommit을 한번 설정하면 수정이 필요없다.이렇듯 간단히 transaction의 기능을 나타낼 수 있다. 실제로 우리가 Declarative Transaction management 방식으로 transaction을 관리할 때 사용하는 @Transactional
은 위와 같은 방식으로 구현이 되어있다.
그렇다면 스프링에서는 @Transactional
을 명시하는 것과 같은 간단한 방식으로 어떻게 기능을 적용해줄까?
@EnableTransactionManagement
를 명시해주어야 한다. (Spring boot에서는 자동 적용)위와 같이 간단한 방법으로 @Transactional
의 기능을 적용할 준비를 할 수 있다. 1번의 경우 Spring boot에서 자동으로 적용을 해준다고 했고,, 그렇다면 2번은 어떻게 하면 될지 알아보자.
@Primary
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
방법은 간단하다. Spring Configuration에 개발자가 원하는 구체적인 TransactionManager의 구현체를 명시해주면 된다.
하지만 Spring boot를 통해 @Transactional
을 사용하면서 Transaction manager를 명시하지 않은 개발자들이 많을 것이다. 별도의 설정없이 우리의 어플리케이션은 어떻게 동작하고 있을까라는 고민을 자연스레 하게되었다.
이유는 아주 간단했다. 초기에 설명했던 AutoConfiguration이 바로 그 답이였다. mybatis-spring-boot-starter-x.jar
를 보면 xml로 작성된 dependency file인 pom.xml
이 있다. 해당 파일을 보자.
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
...
위와 같이 spring-boot-starter-jdbc 의존성이 있는 것을 확인할 수 있다.
Spring Boot의 경우, spring-boot-autoconfigure에서 모든 spring-boot-starter-x의 설정을 책임지고 있으므로 해당 패키지를 확인해보았다. org.springframework.boot.autoconfigure.jdbc
내의 DataSourceTransactionManagerAutoConfiguration
이 그동안 찾던 해답을 가지고 있었다.
@Bean
@ConditionalOnMissingBean(TransactionManager.class)
DataSourceTransactionManager transactionManager(Environment environment, DataSource dataSource,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
DataSourceTransactionManager transactionManager = createTransactionManager(environment, dataSource);
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}
결국 mybatis를 사용할 때, Spring Boot에 의해 mybatis의 의존성과 jdbc의 의존성을 모두 주입받게 되고 이 때 이루어지는 자동설정으로 TransactionManager가 확정된다. 덕분에 우리는 Spring boot를 사용하면 별도의 설정없이도 @Transactional
을 사용할 수 있다.