[Gradle] build.gradle sourceSet 설정 (feat. resource 디렉터리와 mapper)

결론부터.

mapper.xml 파일을 resources에 넣고 싶지 않은 개발자들은 build.gradle 파일에 sourceSet 셋팅을 추가해주어야한다.

그러지 않으면  org.apache.ibatis.binding.BindingException이 날 것이고

당신은 애꿎은 namespace만 노려보면서 오타를 찾아 시간을 버릴 것이다.

sourceSets {
    main {
        resources { // 리소스 파일을 찾는다.
            srcDirs = ["src/main/java", "src/main/resources"] // 이 경로에서
            includes = ["**/*.xml", "**/application.properties"] // 이 유형의 파일을
        }
    }
}

XML 파일은 무엇이고 어째서 resources를 기본 폴더로 잡고 있을까?

src/main/java 디렉터리는 일반적으로 소스 코드가 위치하는 곳이다.

XML 파일은 소스 코드가 아니므로,

src/main/resources 디렉터리 내에 위치해야 한다.

MyBatis가 resources 디렉터리를 뒤지는 이유다.

 

그러나 가독성이 좋지 않지... 찾아가기도 어렵고...

 

SourceSet

이 때문에 sourceSet을 사용하는 것이다.

sourceSet은 Gradle의 리소스 복사 기능인데,

빌드 시 XML 파일을 클래스패스에 포함시켜준다.

 

다만... 스프링의 제어기능을 내가 제어해버리기 때문에 스프링의 유연성을 한계짓는다는 단점이 있다.

예를 들어 스프링은 앱을 구동할 때 application.properties 파일을 자동으로 찾아 실행해준다.

그런데 sourceSet을 사용할 경우, application.properties을 찾으라고 명시해주지 않으면, 찾지 못한다.

sourceSets {
    main {
        resources { // 리소스 파일을 찾는다.
            srcDirs = ["src/main/java", "src/main/resources"] // 이 경로에서
            // 이 때 srcDirs에서 resources를 지정하지 않으면 ~.properties 파일도 찾을 수 없게 되어서 앱이 실행되지 못한다.
            // 이걸 지정하는 순간 정말 고대로 여기서 지정한 디렉터리만 검색을 하게 되는 것이다.
            includes = ["**/*.xml", "**/application.properties"] // 이 유형의 파일을
        }
    }
}

 

그래서 xml 파일뿐만 아니라, application.properties파일도 찾으라고 지정을 해줘야하는 것.

 

srcDirs

이 속성을 통해 Gradle에게 프로젝트에서 소스 파일이 어디에 있는지를 알려준다.

includes, exclude

포함할 파일, 배제할 파일의 유형을 지정할 수 있다.


이 아래부터는 삽질 기록이다.

안해도 됨 → application.properties에 아래 값을 코딩하기

mybatis.config-location=classpath:mybatisConfig.xml
mybatis.mapper-locations=**/*.xml

그래도 삽질 덕에 위 코드에 대해 알게 된 점들 정리해본다.

mybatis.config-location 말 그대로 mybatisConfig.xml 파일의 위치를 말한다. (이 때 값을 빈값으로 둔다면, mybatisConfig.xml 파일을 무시한다. 오직 application.properties 설정으로 처리하게 된다.)
mybatis.mapper-locations= 말 그대로 mapper.xml 파일의 위치를 말한다.

's'의 유무를 잘 확인하시길 ㅎ;

 

classpath는 main/resoucres/를 가르킨다.

  classpath*: classpath:
설명 클래스패스 내의 모든 경로에서 일치하는 자원을 찾을 때 클래스패스 내에서 단일 자원을 찾을 때
동작 방식 JAR 파일을 포함하여 클래스패스의 여러 위치에서 일치하는 모든 자원을 로드한다. 클래스패스에서 하나의 위치에서 첫 번째로 일치하는 파일을 로드한다.
사례 classpath*:**/*.xml은 클래스패스의 모든 경로(다중 경로 포함)에서 *.xml 파일을 검색한다. 즉, 여러 경로에 있는 XML 파일들을 모두 로드한다. classpath:mybatisConfig.xml은 클래스패스 내에서 mybatisConfig.xml 파일을 찾고, 첫 번째 일치하는 파일을 로드한다.

안해도 됨 → mybatisConfig.xml에 아래 값을 코딩하기

xml 선언문이 없으면 인식하지 못할 수도 있대서 넣어봤으나 효과는 없었다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

 

xml 파일을 찾으라고 지시해주기. 역시 효과는 없었다.

<mapper resource="org/inin/mycinema/**/*.xml"/>

이 때 온점이 아니라 슬래쉬를 사용하는 것에 대해서 : 온점은 java에서 패키지를 관리할 때 사용하는 방식이므로, mybatis는 경로를 의미하는 슬래쉬를 넣어주는 것이 더 합당하다 볼 수 있겠다.

 

이 값들을 설정할 땐 application.properties나 mybatisConfig.xml이나 둘 중 하나에만 작성하는 게 나은 것 같다. 둘 다 넣으니 충돌나는 것 같음.


안해도 됨 → @MapperScan 사용하기

main 함수가 있는 클래스에 @MapperScan 어노테이션을 사용하라는 말도 많이 있었다.

@MapperScan("org.inin.mycinema")

상위 패키지에서 하위 패키지를 모두 스캔하는 설정.


여담. resouces폴더는 java가 아니므로 . 을 사용하여 접근할 수 없다.

resources 하위는 package경로가 아닌 directory 경로로 접근하게 된다.

만약 resources 밑에 새로운 디렉터리를 추가할 때 '.'을 사용하여 한번에 처리하려고 했다면 문제가 된다.

예를 들어 당신이 새로운 경로를 만들 때 'service.myservice.mapper.helloMapper'라고 경로를 추가했다면 이는

service

ㄴmyservice

    ㄴ mapper

        ㄴ helloMapper 

라는 4레벨 뎁스의 모양이 아니라

service.myservice.mapper.helloMapper 라는 1레벨 뎁스의 경로가 생겨난다는 것이다. 그냥 긴 폴더명인 셈...

그럼 어떻게 하라고...? 디렉터리를 손수 하나하나 추가해주시면 된다. 이런다면 service/myservice/mapper/helloMapper 처럼 경로가 생기게 되는 것이다.

 

어찌보면 점(.)으로 접근하는 package는 자바 시스템의 부속품이니까... resources에서 동작 안하는 건 당연한걸지도...

resources에 mapper를 넣을 생각이 없는 나와는 상관없는 이슈였다만 읽으면서 재밌어서 추가해둔다.

https://chati.tistory.com/164

https://woo-chang.tistory.com/58