Spring Boot 3.2.x 버전을 사용하며 해결했던 이슈들

Changjin·2024년 4월 13일
0
post-thumbnail

늦게나마 김영한 Spring 강의를 듣게 되었다.
이제는 지원하지 않는 Spring Boot 2.7.x 버전을 대신해 3.2.x 버전을 사용하며 발생했던 문제들과 해결 방법을 정리해보았다.

1. No matching variant 오류

프로젝트 첫 생성 후 빌드 시 아래와 같은 오류가 발생하였다.

No matching variant of org.springframework.boot:spring-boot-gradle-plugin:3.x.x was found.

해결방법

  1. FileProject Structure..ProjectSDK
    자바 17 버전으로 설정
  1. Preferences/Settings → Build, Execution, Deployment → Build Tools → Gradle
    Gradle JVM 에서 자바 자바 17 버전으로 설정

회고

프로젝트 구성에서 자바 버전을 설정하는 것은 인지하고 있었으나, Gradle JVM 에서도 버전을 따로 설정해야 한다는 것을 알게되었다. 기존에는 줄곧 Maven 환경을 사용했던 터라 추후 Gradle에 대해서도 추가적인 공부의 필요성을 느꼈다.

2. 로그를 통한 빈 등록 확인 불가

강의를 들으며 아래의 사진과 같이 로그를 통해 스프링 컨테이너에 빈이 등록되는 것을 확인하는 과정이 있었으나, 3.2.x 버전에서는 컴파일 시 별도의 로그가 생성되지 않았다.

  • 해당 문제는 Spring Boot 3.1.x 버전부터 발생한 이슈로, 스프링의 기본 로그 레벨이 DEBUG에서 INFO 레벨로 변경되었기 때문이었다.
  • 참고로 스프링에선 로깅 라이브러리로 logback을 사용하며, logback의 로깅 레벨은 아래와 같다.

해결방법

프로젝트의 src/main/resources/ 위치에 logback.xml 파일을 생성하고 아래의 내용을 추가한다.

<configuration>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

        <encoder>

            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n</pattern>

        </encoder>

    </appender>

    <root level="DEBUG">

        <appender-ref ref="STDOUT" />

    </root>

</configuration>

참고문헌

인프런 질문 - 로그가 갑자기 안나옵니다 ㅠㅠㅠㅠ
Spring Boot 3.1 릴리즈 노트

회고

스프링에서 기본 로깅 라이브러리로 logback을 이용한다는 것을 알게 되었다. 또한 공식 문서에 따르면 application.properties에서 logging.threshold.consolelogging.threshold.file옵션을 기본적으로 제공하여 콘솔과 파일의 로그 레벨을 별도록 설정하는 기능을 제공한다고 한다. 그러나 해당 기능은 Spring Web 라이브러리가 포함되어 있어야 함으로 Spring Core만 다루는 현재 단계에선 사용해볼 수 없었다. Spring Web 라이브러리가 포함되어 있다면 logback.xml파일을 만들지 않고 application.properties에서 다양한 로그 관련 기능을 설정할 수 있다고 한다.

3. 파라미터 이름 추론 문제

@SpringBootTest 어노테이션이 있는 테스트에서 NoUniqueBeanDefinitionException이 발생하는 문제가 있었다.
오류를 확인해보면 @Autowired@Bean을 통한 수동 빈 등록과 @Component를 이용한 컴포넌트 스캔이 개별적으로 등록되는 것을 확인할 수 있었다.

  • 해당 문제에 대해 정확하게는 Spring Framework 6.1 버전의 변경점 때문이다. (Spring Boot 3.2.x 버전은 Spring Framework 6.1버전을 사용한다.)

  • 아래는 Spring Framework 6.1 의 파라미터 이름 추론과 관련된 변경점에 대한 내용이다.

  • 해당 문서에 따르면 기존에 바이트코드 파싱을 통한 파라미터 이름 추측 기능을 담당하던 LocalVariableTableParameterNameDiscoverer 클래스가 제거되고, Java 8 이상에서 사용되는 -parameters 플래그를 컴파일 시 사용하도록 하는것을 권장한다는 내용이다.

-parameters 플래그와 LocalVariableTableParameterNameDiscoverer 클래스가 제공하는 기능은 유사한 목적을 가지고 있지만, 구현 방식과 세부적인 동작 방식에서 차이가 있다.

  • -parameters 플래그: 해당 플래그는 Java 컴파일러에게 메소드 파라미터의 이름을 클래스 파일에 포함시키도록 지시하여 리플렉션을 통해 메소드 파라미터의 이름을 정확하게 알아내는 방법이다. 이 방법은 더 명확하고 안정적인 방법으로 간주된다.

  • LocalVariableTableParameterNameDiscoverer 클래스: 해당 클래스는 클래스 파일을 직접 파싱하여 파라미터 이름을 추론합니다. 이 방법은 컴파일러나 코드가 특정 방식으로 작성되지 않은 경우 정확하지 않을 수 있다. 즉, 바이트코드 수준에서 파라미터 이름을 추출하는 과정에서 예외 상황이나 불확실성이 발생할 수 있다는 단점이 있다.

해결 방법 1 (권장)

어노테이션에 이름을 생략하지 않고 다음과 같이 항상 적어준다. 이 방법을 권장한다.

@RequestParam("username") String username
@PathVariable("userId") String userId
@Qualifier("memberRepository") MemberRepository memberRepository

개발 환경이 개인이거나 완벽하게 통합된 환경이 아니라면 모든 환경에서 이후에 나오는 -parameters옵션의 적용 여부를 확신할 수 없기 때문에 개발 단계에서 명시적으로 작성하는 것이 바람직하다고 한다.

해결 방법 2 (강의 실습 중 권장)

컴파일 시점에 -parameters 옵션 적용

  1. IntelliJ IDEA에서 FileSettings를 연다. (Mac은 IntelliJ IDEA → Settings)
  2. Build, Execution, DeploymentCompilerJava Compiler로 이동한다.
  3. Additional command line parameters라는 항목에 -parameters를 추가한다.
  4. out 폴더를 삭제하고 다시 실행한다. 꼭 out 폴더를 삭제해야 다시 컴파일이 일어난다.

Spring Core 기본편 강의에서는 바이트코드를 이용한 파라미터 추론을 확인 및 충돌 관련 테스트가 존재한다. 최대한 강의 진행에 차질이 없도록 문제가 되는 코드들을 주석처리하거나 파일을 삭제하는 것보단 -parameters 옵션을 적용하는 것이 적어도 강의 중에는 바람직한 방법이라고 생각했다.

해결 방법 3

Gradle을 사용해서 빌드하고 실행한다.

참고로 이 문제는 Build, Execution, DeploymentBuild ToolsGradle에서
Build and run using를 IntelliJ IDEA로 선택한 경우에만 발생한다. Gradle은 기본적으로 -parameters옵션이 활성화 되어 있기 때문에 해당 문제가 발생하지 않는다.

참고문헌

인프런 질문 - 전체 테스트 중 CoreApplicationTests 클래스의 contextLoads 테스트 실패 질문입니다.
Spring 6.1에서 변경된 Parameter Name Retention
Spring Framework 6.x 문서

회고

해당 문제에 대해 찾아보며 한 블로그를 통해 왜 이렇게 변경되었는지 알 수 있었다.

기존의 JVM에서 Spring을 실행하는 것과 달리 Native로 실행하면 다양한 제약이 생겨난다. 이러한 제약을 극복하기 위해서 Spring Native는 다양한 방법으로 이를 해결하고 있지만 여전히 지원되지 않는 기능들도 존재한다. 이러한 것들을 극복하기 위해서 Spring 프레임워크도 Native Image와 호환성을 높이는 방향으로 나아가고 있고, 그 과정에서 내려진 결정으로 보인다.

Spring Framework가 네이티브 환경에서의 호환성을 높이고 표준을 준수하는 것을 목표로 한다는 것을 알 수 있었다. 결국 Spring 또한 Java를 사용하기에 더 편리하게 돕는 도구이지, 기본이 되는 Java에서 멀어져선 안된다는 것을 보여주는 변경점이었다고 생각했다.

profile
🦕 궁금한게 많은 주니어 개발자

0개의 댓글

관련 채용 정보