IT/SpringBoot

SqlSessionFactoryBean setMapperLocations에 mapper.xml 여러 개 등록하기

twofootdog 2022. 3. 17. 13:56

이번 글에서는 스프링부트에서 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()]);
    }
}​

 


참고

http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/jacoco/org.mybatis.spring.boot.autoconfigure/MybatisProperties.java.html

 

MybatisProperties.java

 

mybatis.org