💡 FCM 키워드 알람 테스트를 하려고 개발을 마친 후 개발계에서 배포하고 테스트를 진행하려다가 발생한 문제에 대한 해결 과정 기록
문제 상황
./gradlew build -x test로 빌드- scp 명령어를 통해 빌드 산출물인 jar 파일을 로컬 → Bastion 서버 → 개발계 private 서버로 옮김
- 개발계에서
nohup java -jar [jar 파일명] &으로 jar 파일을 실행시키려고 했을 때 에러가 발생한다. - 로컬에서는 잘만 실행된다. (^R로 실행)
Error 로그
no main manifest attribute, in poppin-server-0.0.1-SNAPSHOT.jar
2024-09-06T16:40:35.129Z INFO 1165 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor : Failed to shut down 1 bean with phase value 2147481599 within timeout of 30000ms: [webServerStartStop]
2024-09-06T16:40:35.136Z WARN 1165 --- [ionShutdownHook] o.s.b.f.support.DisposableBeanAdapter : Custom destroy method 'shutdown' on bean with name 'amazonS3Client' propagated an exception: java.lang.NoClassDefFoundError: org/apache/http/impl/conn/PoolingHttpClientConnectionManager$2
2024-09-06T16:40:35.148Z INFO 1165 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2024-09-06T16:40:35.150Z WARN 1165 --- [ionShutdownHook] o.s.b.f.support.DisposableBeanAdapter : Invocation of destroy method failed on bean with name 'entityManagerFactory': java.lang.NoClassDefFoundError: org/springframework/orm/hibernate5/SpringBeanContainer$SpringContainedBean
2024-09-06T16:40:35.151Z INFO 1165 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : jpa-hikari-pool - Shutdown initiated...
2024-09-06T16:40:35.153Z INFO 1165 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : jpa-hikari-pool - Shutdown completed.
Exception in thread "SpringApplicationShutdownHook" java.lang.NoClassDefFoundError: org/apache/catalina/Lifecycle$SingleUse
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:254)
at org.apache.catalina.startup.Tomcat.stop(Tomcat.java:498)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.stopTomcat(TomcatWebServer.java:277)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.destroy(TomcatWebServer.java:350)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.doClose(ServletWebServerApplicationContext.java:177)
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:1037)
at org.springframework.boot.SpringApplicationShutdownHook.closeAndWait(SpringApplicationShutdownHook.java:145)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at org.springframework.boot.SpringApplicationShutdownHook.run(SpringApplicationShutdownHook.java:114)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.lang.ClassNotFoundException: org.apache.catalina.Lifecycle$SingleUse
... 10 more
문제 원인
no main manifest attribute
spring 애플리케이션을 빌드한 결과물로 나온 jar파일에서
JVM이 처음 호출할 Main 메소드를 MANIFEST.MF에서 찾게 되는데, 찾지 못했다는 에러다.
운영계(prd)에서 Private 서버의 CI/CD를 구축하다가 다음과 같은 코드가 추가되었었다.
jar {
archiveFileName.set('poppin-server-0.0.1-SNAPSHOT.jar')
}
build Task로 원래 [앱 이름]-plain.jar 을 생성하는 데 archiveFileName.set('poppin-server-0.0.1-SNAPSHOT.jar') 코드로 인해 의존성이 다 빠진 plain이지만, 이름으로 인해 plain이 아닌 듯한 jar 파일이 생성된 것이다 (….)
plain.jar은 의존성을 제외하고 jar로 만든것으로 spring 관련 의존성이 빠져 MANIFEST.MF에 Main메소드의 위치가 나오지 않는다.
이 때, plain.jar를 java -jar로 실행하면 no main manifest attrubute in 에러가 발생하는 것이다.
시도 및 해결
시도 1) build.gradle에 다음과 같은 코드를 추가했다.
jar {
manifest {
attributes(
'Main-Class': 'com.poppin.poppinserver.PoppinServerApplication'
)
}
}
다음과 같은 ClassNotFoundException이 발생했다.
Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication
at com.poppin.poppinserver.PoppinServerApplication.main(PoppinServerApplication.java:17)
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
... 1 more
시도 2) [앱 이름]-plain.jar 파일이 아닌 [앱 이름].jar 파일을 만들고 java -jar로 실행시킨다.
gradlew로 빌드를 할 때 jar파일이 2개 생성된다.
- bootJar Task로 [앱이름].jar 이 생성
- build Task로 [앱 이름]-plain.jar 이 생성
[앱 이름].jar 파일은 프로젝트에 필요한 모든 의존성이 추가된 것으로 MANIFEST.MF까지 모두 정상적인 형태로 나온다.
[앱 이름]-plain.jar를 생성하지 않기 위해서 기존의 코드를 지우고 아래 명령어를 build.gradle에 추가
jar {
enabled = false
}
그리고 다음과 같은 코드를 추가한다.
bootJar {
archiveFileName.set "poppin-server-0.0.1-SNAPSHOT.jar"
}
./gradlew clean build -x test 로 다시 jar 파일을 만들고 개발계 서버로 옮긴다.
다시 nohup java -jar 로 실행

해결
'project > poppin-server' 카테고리의 다른 글
| @Transactional 최적화 (0) | 2024.08.03 |
|---|---|
| Refresh Token Rotation을 통한 보안 강화 (0) | 2024.08.01 |