mybatis-spring 프레임워크를 사용할 때 mapper를 springContext에 주입하는 방법으로 크게 2가지가 있습니다
- Mapper 수동 등록
- Mapper 스캔을 이용한 자동 등록
두가지 방법을 알아보겠습니다.
목차
Mapper 수동 등록하기
- XML설정 사용
- 자바설정 사용
Mapper 수동등록은 XML을 이용한 Mapper 등록을 알아보겠습니다.
XML설정 사용
매퍼는 다음처럼 XML설정파일에 MapperFactoryBean
을 두는 것으로 스프링에 등록됩니다.
1
2
3
4
5
<!--1. Mapper 등록-->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.gil.mybatis.mapper.MyBatisMapper" />
<property name="sqlSessionTemplate" ref="sqlSessionTemplate" />
</bean>
Mapper 스캔
Mybatis는 스프링과 같이 사용 할 때 Dao(Mapper) 를 빈에 주입할 수 있는 다양한 방법을 제공합니다.
<mybatis:scan/>
엘리먼트 사용@MapperScan
애노테이션 사용- 스프링 XML파일을 사용해서
MapperScannerConfigurer
를 등록
2번 방법은 1번방법과 xml방식 클래스방식의 차이만 있을 뿐 같은 기능이기 때문에 따로 다루지 않겠습니다.
I. mybatis:scan 엘리먼트 사용
기본적으로 제일 편리하고 사용하기 쉬운 방법입니다.
<mybatis:scan/>
은 다음과 같은 속성을 가지고 있습니다.
- base-package ( required )
- annotation
- marker-interface
- factory-ref
- template-ref
- default-scope
- lazy-initialization
- mapper-factory-bean-class
- name-generator
이 글에서는
- base-package
- annotation
- marker-interface
를 알아보겠습니다.
base-package
mapper를 주입시켜줄 package를 지정합니다.
1
<mybatis:scan base-package="com.gil.mybatis.mapper"/>
해당 패키지에 아래에 있는 모든 interface들을 mapper로 등록해 줍니다.
annotation
mapper를 검색할 annotation을 등록할 수 있습니다.
<mybatis:scan/>
설정
1
<mybatis:scan base-package="com.gil.mybatis.mapper" annotation="com.gil.utils.GilMapper" />
mapper를 명시해줄 annotation
1
2
3
4
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface GilMapper{
}
<mybatis:scan/>
엘리먼트에 annotation 속성을 추가하여 basePackage 내의 mapper들을 필요에 따라 필터링 할 수 있습니다.
2개의 mapper가 basePackage 내에 만들어져 있습니다.
1
2
3
4
5
6
7
8
@GilMapper
public interface MyBatisMapper {
MybatisVo requestUser();
}
public interface MyBatisMapper2 {
MybatisVo requestUser();
}
위 코드와 같이 둘 중 하나의 Mapper에게 어노테이션을 부여하였습니다.
테스트 코드
1
2
3
4
5
6
7
8
9
10
11
@Test
@DisplayName("Mapper 주입 테스트")
public void mapperInjectTest(){
assertDoesNotThrow(() -> {
MyBatisMapper myBatisMapper1 = context.getBean(MyBatisMapper.class);
}, "MyBatisMapper1 은 null 입니다.");
assertDoesNotThrow(() -> {
MyBatisMapper2 myBatisMapper2 = context.getBean(MyBatisMapper2.class);
}, "MyBatisMapper2 은 null 입니다.");
}
위 두 mapper인터페이스 중 하나의 mapper에만 어노테이션을 부여하여 원하는 의도대로 mapper스캔이 이루어 졌는지 assertDoesNotThrow메소드를 이용하여 context에 등록되지 않았다면 오류메세지가 출력되도록 테스트코드를 작성하였습니다.
결과
예상대로 어노테이션이 입력되지 않은 mapper가 context에 등록되지 않아 NoSuchBeanDefinitionException 을 발생시키는 걸 볼 수 있습니다.
marker-interface
marker-interface
프로퍼티는 검색할 상위 인터페이스를 지정할 수 있습니다.
<mybatis:scan/>
설정
1
<mybatis:scan base-package="com.gil.mybatis.mapper" marker-interface="com.gil.utils.BaseGilMapper" />
상위 인터페이스
1
2
3
public interface BaseGilMapper {
MybatisVo requestUser();
}
상위 인터페이스를 상속받은 mapper
1
2
public interface MyBatisMapper extends BaseGilMapper {
}
위와 같이 marker-interface로 설정해준 상위 인터페이스를 상속받은 mapper 인터페이스만 context에 등록 되게 됩니다. 동시에 상위 인터페이스의 메소드를 사용함으로써 자주 사용하는 기능들을 매번 작성해야하는 수고를 덜 수 있습니다.
MyBatisMapper를 namespace로 가지는 xml
1
2
3
4
5
6
7
<mapper namespace="com.gil.mybatis.mapper.MyBatisMapper">
<select id="requestUser" resultType="mybatisVo">
select *
from tb_user
limit 1
</select>
</mapper>
테스트 코드
1
2
3
4
5
6
7
8
9
10
11
@Test
@DisplayName("Mapper 주입 테스트")
public void mapperInjectTest(){
assertDoesNotThrow(() -> {
MyBatisMapper myBatisMapper1 = context.getBean(MyBatisMapper.class);
}, "MyBatisMapper1 은 null 입니다.");
assertDoesNotThrow(() -> {
MyBatisMapper2 myBatisMapper2 = context.getBean(MyBatisMapper2.class);
}, "MyBatisMapper2 은 null 입니다.");
}
테스트 코드는 위의 annotation 프로퍼티를 이용한 테스트와 같은 조건으로 MyBatisMapper 인터페이스만 상위 인터페이스 상속을 받아 진행하였습니다.
결과
상위 인터페이스를 상속받은 mapper인터페이스 만 context에 주입되는 것을 확인 할 수 있습니다.
또 한가지
저는 marker-interface
를 이용한 상속 방법이 과연 xml매퍼 파일로 등록된 쿼리문을 실행시킬 수 있을지 궁금하였습니다.
테스트 코드
marker-interface
를 상속받은 MyBatisMapper의 requestUser
메소드를 실행하는 service 클래스입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
public class MyBatisServiceImpl implements MyBatisService {
private final MyBatisMapper myBatisMapper;
public MyBatisServiceImpl(MyBatisMapper myBatisMapper) {
this.myBatisMapper = myBatisMapper;
}
@Override
public MybatisVo requestTest1() {
return myBatisMapper.requestUser();
}
}
1
2
3
4
5
6
7
8
9
@Test
@DisplayName("유저 조회 테스트")
public void userSelectTest(){
MybatisVo mybatisVo = myBatisService.requestTest1();
System.out.println("--------------------------------");
System.out.println("mybatisVo = " + mybatisVo);
System.out.println("--------------------------------");
}
결과
marker-interface
를 상속받은 메소드도 xml매퍼 파일에 접근이 가능하다는걸 볼 수 있습니다.
II. 스프링 XML파일을 사용해서 MapperScannerConfigurer
를 등록
1
2
3
4
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.gil.mybatis.mapper"/>
<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
</bean>
MapperScannerConfigurer을 bean으로 등록해주는 방법으로도 mapper들을 등록할 수 있습니다.
Github source
references