SqlSessionFactoryBean setMapperLocations에 mapper.xml 여러 개 등록하기
이번 글에서는 스프링부트에서 mybatis 사용 시, SqlSessionFactoryBean의 setMapperLocations 메소드에 mapper.xml을 여러 개 등록하는 방법에 대해 알아볼 것이다.
우선 스프링부트 서비스에서 DB에 접근하기 위해서는 application.yml 파일에 DB 접속정보를 작성하게 되는데, 여러 개의 DB에 접근해야 하는 경우는 별도의 Java Config 작성 후, @MapperScan 어노테이션에 해당 DB 에 접근하는 SQL mapper 인터페이스의 패키지 위치를 작성하고, SqlSessionFactoryBean의 setMapperLocations 메소드로 mapper.xml의 위치를 지정해주게 된다.
<전체 코드>
package com.project.common.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Configuration
@MapperScan(basePackages = {"com/project/domain/first*/mapper"}, sqlSessionFactoryRef = "firstDbSqlSessionFactory")
public class FirstDbConfig {
private static final Logger log = LogManager.getLogger();
private final ApplicationContext applicationContext;
public FirstDbConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
// First DB에 접근 가능한 DataSource Bean 등록
@Primary
@Bean(name = "firstDataSource")
@ConfigurationProperties("spring.datasource.first")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
// First DB 용 sqlSessionFactory Bean 등록
@Primary
@Bean(name = "firstDbSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("firstDataSource") DataSource dataSource) throws Exception {
final SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/config/mybatis-config.xml"));
factoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/mapper/*.xml"));
return factoryBean.getObject();
}
// First DB 용 TransactionManager Bean 등록
@Primary
@Bean(name = "firstDbTransactionManager")
public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("firstDataSource") DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
여기서 setMapperLocations에 여러 개의 mapper.xml 위치를 등록하기 위해 별표(*)을 사용했는데(예를 들면 applicationContext.getResources("classpath:mybatis/mapper/*.xml")),
만약 setMapperLocations에 mapper 위치 규칙을 여러 개(List 형태)로 입력하기 위해서는 별도의 메소드를 구현해 줘야 한다.
다음 예제에서는
com/project/domain/dog*/mapper, com/project/domain/cat*/mapper 패키지 내에 mapper 인터페이스가 존재하고,
resources/mybatis/mapper/dog*/*.xml, resources/mybatis/mapper/cat*/*.xml에 mapper.xml이 존재하고, 해당 mapper가 first DB라는 데이터베이스에 접근하는 경우에 대한 코드이다.
<전체 코드>
package com.project.common.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Configuration
@MapperScan(basePackages = {"com/project/domain/dog*/mapper", "com/project/domain/cat*/mapper"}, sqlSessionFactoryRef = "firstDbSqlSessionFactory")
public class FirstDbConfig {
private static final Logger log = LogManager.getLogger();
private final ApplicationContext applicationContext;
public FirstDbConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
// First DB에 접근 가능한 DataSource Bean 등록
@Primary
@Bean(name = "firstDataSource")
@ConfigurationProperties("spring.datasource.first")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
// First DB 용 sqlSessionFactory Bean 등록
@Primary
@Bean(name = "firstDbSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("firstDataSource") DataSource dataSource) throws Exception {
final SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/config/mybatis-config.xml"));
factoryBean.setMapperLocations(resolveMapperLocations());
// factoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/mapper/*.xml"));
return factoryBean.getObject();
}
// First DB 용 TransactionManager Bean 등록
@Primary
@Bean(name = "firstDbTransactionManager")
public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("firstDataSource") DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
// First DB 용 Mapper xml 리스트를 리턴해주는 메소드
public Resource[] resolveMapperLocations() {
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
List<String> mapperLocations = new ArrayList<>();
mapperLocations.add("classpath:mybatis/mapper/dog*/*.xml");
mapperLocations.add("classpath:mybatis/mapper/cat*/*.xml");
List<Resource> resources = new ArrayList<>();
if (!mapperLocations.isEmpty()) {
for (String mapperLocation : mapperLocations) {
try {
Resource[] mappers = resourceResolver.getResources(mapperLocation);
resources.addAll(Arrays.asList(mappers));
} catch (IOException e) {
log.error("Mybatis resources Get Exception Occur", e);
}
}
}
return resources.toArray(new Resource[resources.size()]);
}
}
참고