IDE/IntelliJ

자바의 빌드 시스템, Gradle Build와 IntelliJ Build

헹창 2022. 9. 1.
반응형

컴파일과 빌드

요즘에는 IDE가 워낙 좋아져 컴파일과 빌드의 차이를 모르는 경우가 많다.(=나) 왜냐하면 대부분 툴에서 그 둘을 동시에 Run 하나로 퉁치기 때문이다.

  • 컴파일 : 소스의 문법을 분석해 기계어로 번역, 자바의 경우 JVM(Java Virtual Machine)에서 실행 가능한 바이트코드 형태의 클래스 파일이 생성된다.
  • 링크 : 소스 파일이 여러 개 생성되고, 소스파일에서 각 함수를 호출하는 경우가 있으므로, 연결작업을 해주는 것을 링크라 한다.
  • 빌드 : 빌드는 컴파일이 포함된 일종의 과정으로, 프로그래밍 된 코드를 컴파일하고 실행 가능한 결과물로 만드는 과정을 칭한다. 컴파일과 링크가 빌드 안에 포함되는 개념이라 볼 수 있다.

자바의 빌드 시스템

  • Maven
  • Gradle
  • IntelliJ

Maven

  • 전통적인 빌드 툴로, Apache ANT의 대안으로 시작되었으며 자바 프로젝트의 전체적인 관리를 가능하게 함과 동시에 많은 편리함, 이점을 제공해준다.
  • Project Object Model을 관리하는 pom.xml 파일을 사용하며 개발자가 해당 파일에 사용할 라이브러리를 정의해 두면 정의된 라이브러리 뿐 아니라 그 라이브러리를 사용하는 데 필요한 종속된 라이브러리까지 관리해 자동으로 다운로드해 사용할 수 있다.
  • 빌드 동작이 미리 정해져 있고, 라이프 사이클에 의해 순서에 맞게 동작한다.

Gradle

  • Maven보다 늦게 만들어진 빌드 툴로, 기존 ANT와 Groovy 기반으로 구축되어 ANT 역할과 배포 기능 모두 지원한다.
  • Maven에 비해 더 나은 사용성과 성능을 제공하며, 안드로이드 앱의 공식 빌드 시스템으로 Java, C/C++, Python 등 다양한 언어에 대한 빌드를 지원한다.
  • Maven과 달리 build.gradle 파일을 사용하며 Maven과 동일하게 개발자가 사용할 라이브러리를 정의해 둘 수 있다. 마찬가지로 정의된 라이브러리 + 종속된 라이브러리까지 관리해 자동 다운로드하여 사용할 수 있다.

IntelliJ

  • IntelliJ에서 제공하는 독자적인 빌드 방식이다. IntelliJ 빌드 시스템은 IntelliJ 자체 빌드 매커니즘으로 단순하게 프로젝트의 모든 수정 내용과 종속 파일을 컴파일 하는 기능으로, 수정 내용과 종속된 파일만 빌드한다.
  • 증분 빌드(incremental build) 란, 증분된 부분, 즉 변경된 부분만 빌드하는 방식으로 변경되지 않은 것에 대해서는 건너뛰고 빌드를 진행해서 빠른 빌드를 원할 경우 선택하는 방법이다. IntelliJ가 바로 증분 빌드이다. 그래서 IntelliJ IDEA가 Gradle 빌드 방식보다 빠르게 빌드를 수행할 수 있는 것이다.

 

또한, Gradle build 시 build 폴더로 빌드 결과물이 나오고, IntelliJ build 시 out 폴더로 빌드 결과물이 나온다.

 

Gradle vs IntelliJ Build 이슈

빌드 속도가 빠르다고 해서 마냥 성능이 좋다고만 할 수 없는 사례가 있다.

 

  1. 이 링크(게시글)를 보면 삭제한 파일에 대해 변경사항이 없다고 판단해 건너뛰고 빌드를 진행해 삭제됐던 파일이 포함된 상태로 빌드가 되어 오류가 발생했다고 한다.
  2. 내가 겪은 이슈는, JPA repository에서 @Query 를 작성하여 parameter를 넘길 때 Gradle 빌드와 IntelliJ 빌드의 차이가 발생했다.

JPA 이슈 예제

Spring Data JPA 의 파라미터 바인딩 방법이 2가지가 있는데, 위치 기반(기본 값)과 이름 기반 바인딩 방법이 있다.

// 위치 기반
@Query("select u from User u where u.id = ?1")
Optional<User> findById1(String userId);

// 이름 기반
@Query("select u from User u where u.id = :userId")
Optional<User> findById2(@Param("userId") String id);

하지만, 공식문서를 보면 java 8 버전 이상부터는 리플렉션을 통해 메서드 파라미터의 이름에서 JPQL 파라미터의 이름을 추론할 수 있다고 한다. 추가로 -parameters 라는 Compiler flag 설정을 같이 해주면 @Param 을 넣지 않아도 메서드의 매개변수 이름에 접근할 수 있어 바인딩이 정상 동작한다는 것이다.

@Query("select u from User u where u.id = :userId")
Optional<User> findById2(String id);

 

이 때, 나는 위와 같이 @Param 을 생략한 이름 기반으로 파라미터를 바인딩 시켰고, -parameters flag를 설정하지 않고 사용했다. 그런데, Gradle build의 경우 정상적으로 동작하였고, IntelliJ build 방식으로 설정한 경우 다음과 같은 오류가 발생했다.

For queries with named parameters you need to use provide names for method parameters. 
Use @Param for query method parameters, or when on Java 8+ use the javac flag -parameters.

 

왜 Gradle일 때는 -parameters Compile flag 설정하지 않았는데도 정상적으로 동작하는 지 의문이 들어서 이렇게 먼 길을 돌아온 것이다.

 

여기서 -parameters 컴파일 설정을 Settings > Build, Execution, Deployment > Compiler > Java Compiler 에서 "Additional command line parameters:" 에서 설정을 안했는데?? 로만 생각했었는데,

이제 보니 build.gradle 쪽에 compileJava 설정을 해줬었던 것이다.. 

compileJava.options.compilerArgs << '-parameters'

코드를 제대로 살펴보지도 않고 무턱대고 왜안돼!! 만 외치다가.. 굉장히 먼 길을 돌아왔다... ㅠ

 


참고

https://www.jetbrains.com/help/idea/gradle-settings.html

https://docs.microsoft.com/ko-kr/visualstudio/msbuild/incremental-builds?view=vs-2022

https://jobc.tistory.com/202

https://smoh.tistory.com/467

https://pamyferret.tistory.com/m/62

 

 

728x90
반응형

댓글

추천 글