저는 STS로 개발을 시작했기 때문에 STS에 모든 프로젝트들을 모아놓고 작업을 했습니다. 하나의 workspace에 모든 프로젝트들을 넣어두고 사용하는 프로젝트만 열어서 개발하는 방식이었습니다. 그런데 어느날 STS를 실행했는데 갑자기 에러가 발생했습니다. 그리고 workspace와 연결된 프로젝트 설정이 모두 날아갔습니다.
실제 프로젝트 폴더와 파일들이 없어지진 않았지만 프로젝트의 수가 꽤 되었기 때문에 workspace를 정리하고 프로젝트들을 복구하는데 많은 시간을 들여야했습니다. 그리고 크기가 큰 프로젝트를 다룰 때 자주 STS가 멈췄기 때문에 언젠가는 VS code로 바꿀 생각이었습니다. 마침내 때가 온 것이죠.
프로젝트를 옮기는 건 어려운 일이 아니었습니다. 작업공간을 구성하고 폴더를 추가하면 끝이니까요. 물론 extension을 설치하고 설정하는게 귀찮기는 합니다. 문제는 디버깅이었습니다.
Spring boot는 extension에서 디버깅 기능을 지원합니다. 하지만 boot가 아닌 spring framework에서는 STS와 같은 디버깅을 VS code에서 할 수 없었습니다. Spring으로 개발한 웹 앱 프로젝트는 서버를 구동해서 디버깅을 해야하는데 별도의 extension이 존재하지 않기 때문입니다.
검색을 해보면 대부분 Tomcat for Java를 설치하라고 권장하지만 이 extension은 좀 문제가 많습니다.
Hot code replacement 기능은 디버깅을 하는 도중에 수정한 파일들을 즉시 업데이트하는 기능입니다. STS에서도 똑같은 기능을 지원하지만 큰 프로젝트를 다루면 종종 툴이 멈추는 원인이기 때문에 수동으로 빌드하고 했습니다.
어쨌든 Tomcat for Java는 오직 Java 파일만 가능하고 js나 jsp를 수정하기 위해선 직접 deploy된 경로에 가서 해당 파일을 열어서 수정해야 합니다. 아니면 디버깅을 새로 할 때마다 war 파일을 다시 만들어서 deploy를 해야합니다. 너무 번거롭죠.
그래서 boot가 아닌 Spring framework도 boot처럼 디버깅할 수 없을까라고 생각하게 되었습니다.
VS code는 외부 디버거와 연결할 수 있습니다. 그러기 위해선 launch.json
이라는 파일을 작성해서 설정해야 합니다.
launch.json
은 .vscode
폴더 안에 위치합니다. 폴더가 없다면 VS code의 디버깅 사이드 메뉴를 열어서 launch.json
을 작성할 수 있습니다.
작업 순서는 다음과 같습니다.
1. launch.json
작성.
2. tasks.json
작성.
3. pom.xml
에 maven plugin 설정 추가.
아래의 코드를 참고하여 launch.json
을 작성하면 됩니다. launch.json
은 같은 디렉토리에 있는 tasks.json
을 참조하여 preLaunchTask
와 postDebugTask
를 수행합니다.
{
"version": "0.2.0",
"configurations": [
{
"type": "java", // 디버깅의 타입을 정의.
"name": "Test Debug", // 디버깅 설정 목록에서 표시할 이름.
"request": "attach", // 디버깅의 요청 형식을 정의. 'launch' 또는 'attach'.
"hostName": "localhost", // 원격 디버거(여기선 메이븐)의 호스트 네임.
"port": 8000, // 원격 디버거의 포트.
"preLaunchTask": "run-tomcat", // 디버깅 세션이 실행되기 전에 수행될 task.
"postDebugTask": "stop-tomcat", // 디버깅 세션 종료 후 수행될 task.
}
]
}
이 파일을 작성할 때의 주의점은 반드시 파일명을 tasks로 해야 합니다. 그리고 launch.json
과 같은 디렉토리인 .vscode
폴더에 위치해야 합니다.
{
"version": "2.0.0",
"tasks": [
{
"label": "run-tomcat", // launch.json에서 사용할 task 이름.
"type": "shell", // task의 타입.
"command": "./mvnDebug -f \"./pom.xml\" -s \"./settings.xml\" tomcat7:run", // task로 실행할 명령어.
"group": "build", // task를 할당할 그룹. 'build' 또는 'test' 이다.
"isBackground": true, // task를 백그라운드에서 실행할 것인지에 대한 설정.
"problemMatcher": [{ // 문제를 찾기위한 설정.
"pattern": [{
"regexp": "\\b\\B",
"file": 1,
"location": 2,
"message": 3
}],
"background": {
"activeOnStart": true,
"beginsPattern": "^.*Listening for",
"endsPattern": "^.*transport dt_socket at address.*"
}
}]
},
{
"label": "stop-tomcat",
"type": "shell",
"command": "echo ${input:terminate}}", // 하단 inputs 오브젝트 참고.
"problemMatcher": []
}
],
"inputs": [
{
"id": "terminate",
"type": "command",
"command": "workbench.action.tasks.terminate",
"args": "run-tomcat"
}
]
}
tasks.json 참고 링크: [Github] Microsoft / vscode-java-debug
여기서 command 부분이 중요한데, 디버깅하려는 프로젝트의 pom.xml
을 옵션으로 넣어줘야 합니다. 당연히 maven도 설치되어 있어야 합니다. mvnDebug
는 아파치 메이븐에 포함되어 있는 프로그램입니다.
pom.xml
파일을 열어보면 하단에 <build>
라는 태그가 있고 그 아래에 plugin들을 기술합니다.
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<server>Tomcat</server>
<path>/</path>
<charset>UTF-8</charset>
<uriEncoding>UTF-8</uriEncoding>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-util</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-coyote</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-api</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jsp-api</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper-el</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-el-api</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-tribes</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina-ha</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-annotations-api</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>7.0.109</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-log4j</artifactId>
<version>7.0.109</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
tomcat 버전들을 특정한 이유는 java9 환경에서 일부 jar를 사용할 수 없는 에러가 발생하기 때문입니다. 오류 로그를 보면 아래와 같은 메시지를 확인할 수 있습니다.
Invalid byte tag in constant pool: 19
최신 버전에서는 해당 오류가 해결되었기 때문에 tomcat7의 최신 버전을 사용했습니다.
tomcat 버그 참고 링크: https://bz.apache.org/bugzilla/show_bug.cgi?id=60688
tasks.json
을 보면, run-tomcat
의 mvnDebug tomcat:run
를 실행하고 maven이 pom.xml
의 톰캣 플러그인을 디버깅 모드로 실행하게 됩니다. 이때 기본 포트로 8000번이 설정되는데 포트를 변경하고 싶다면 mvnDebug
파일을 열어서 값을 수정해야합니다.
launch.json
이 mvnDebug의 hostname과 port로 vscode 디버거를 연결합니다.
설정이 다 됐다면 VS code의 디버깅 사이드 메뉴에서 launch.json
에서 설정한 이름을 찾고 디버깅을 실행합니다. 이틀 동안의 삽질이 빛을 보는 순간이었습니다.