지원 스펙 / 프로그래밍 모델
구분 | Tomcat | TomEE |
기본 | Servlet, JSP/EL, WebSocket | Tomcat + Jakarta EE Web Profile 계열 기능들 |
DI | 없음(직접 프레임워크 필요) | CDI(@Inject) 기본 제공 |
트랜잭션 | 로컬 트랜잭션만(직접 관리) | JTA 제공 → CMT/BMT, 분산 트랜잭션 |
영속성 | 없음 | JPA + @PersistenceContext(EntityManager) 주입 |
EJB | 없음 | EJB Lite(예: @Stateless, @Schedule) |
REST | 없음(별도 프레임워크 필요) | JAX-RS 내장(일반적으로 Apache CXF 통합) |
Bean Validation | 없음 | @NotNull 등 기본 제공 |
Spring 기반이면 Tomcat도 충분하지만, JTA 같은 컨테이너 기능은 별도 구성 필요.
리소스/JNDI 구성 방식
Tomcat (보통 server.xml 또는 context.xml)
<Resource name="jdbc/igateMeta" auth="Container"
type="javax.sql.DataSource"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://192.168.56.1:5432/apim"
username="apim" password="1234" />
애플리케이션에서 찾을 때:
- JNDI 이름: java:comp/env/jdbc/igateMeta
- Spring 예: jndiName=java:comp/env/jdbc/igateMeta
TomEE (conf/tomee.xml)
<Resource id="igateMeta" type="javax.sql.DataSource">
JtaManaged = false
JdbcDriver = org.postgresql.Driver
JdbcUrl = jdbc:postgresql://192.168.56.1:5432/apim
UserName = apim
Password = 1234
</Resource>
트랜잭션
- Tomcat: JDBC 로컬 트랜잭션만. 분산 트랜잭션/XA, CMT를 쓰려면 외부 TM(Narayana 등) 또는 Spring TX 설정 필요.
- TomEE: JTA 내장. @Transactional(또는 EJB CMT)로 트랜잭션 경계를 컨테이너가 관리. XA DataSource, 메시징 등과 연계 쉬움.
의존성 주입/표준 어노테이션
- Tomcat: DI/EE 어노테이션 미제공 → Spring/Guice 등으로 해결.
- TomEE: CDI/EE 주입 제공.
@Stateless
public class MyService {
@PersistenceContext EntityManager em;
@Resource(lookup="openejb:Resource/igateMeta") DataSource ds;
public void work() { /* CMT 하에 em 사용 */ }
}
배포/설정 파일 & 클래스로딩
- Tomcat: 리소스는 server.xml/context.xml 중심, 앱은 WEB-INF/lib에 의존성.
- TomEE: EE 스펙 제공 라이브러리들을 이미 포함.
- 중복 위험: 애플리케이션 WEB-INF/lib에 JPA/JTA/CDI 구현체를 또 넣으면 충돌 가능.
- 관례: EE 구현체는 서버가 제공 → 앱에는 API만 두거나 아예 생략.
- 드라이버 위치: DB 드라이버(JDBC)는 보통 ${TOMEE_BASE}/lib(공유) 또는 앱 WEB-INF/lib.
메모리/성능/운영
- Tomcat: 가장 가볍고 빠른 단일 HTTP/서블릿 컨테이너.
- TomEE: Tomcat + EE 기능 로딩으로 메모리/시작시간 조금 증가.
- 대신 표준 EE 스택 일체형이라 운영/구성이 단순해지는 이점이 큼.
- 장애/로그: TomEE는 EE 레이어에서 예외가 표준화되어 추적이 편한 면이 있고, JTA 일관성 유지에 유리.
어떤 경우에 무엇을 쓸까?
- Tomcat 추천
- Spring Boot/Spring Framework 중심 아키텍처
- EE 기능이 굳이 필요 없고 경량/속도 최우선
- 트랜잭션/DI/REST 등을 Spring이 다 처리
- TomEE 추천
- 표준 Jakarta EE(CDI/JPA/JTA/EJB/JAX-RS 등)로 개발/운영
- 컨테이너 관리 트랜잭션 필수(특히 다중 리소스/XA)
- EE 어노테이션 기반 DI와 자원 주입을 선호
- Spring 의존 줄이고 표준 API로 가볍게 가고 싶을 때
여러분 환경에 바로 쓰는 팁 (JNDI)
TomEE에서 여러분 WAR이 Resource/igateMeta로 찾고 있다면 둘 중 하나로 맞출것
<bean id="metaDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="openejb:Resource/igateMeta"/>
</bean>
TomEE에 별칭(jndiName) 부여해서 기존 이름 유지
<Resource id="igateMeta" type="javax.sql.DataSource" jndiName="Resource/igateMeta">
JtaManaged = false
JdbcDriver = org.postgresql.Driver
JdbcUrl = jdbc:postgresql://192.168.56.1:5432/apim
UserName = apim
Password = 1234
</Resource>
Tomcat vs TomEE에서 DataSource 사용
Tomcat + Spring (전통)
<!-- context.xml -->
<Resource name="jdbc/igateMeta" ... />
<!-- Spring -->
<bean class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/igateMeta"/>
</bean>
TomEE + 표준 EE
// EJB/CDI 빈에서 표준 주입
@Resource(lookup = "openejb:Resource/igateMeta")
DataSource ds;
@PersistenceContext
EntityManager em;
@Transactional
public void doWork() { /* 트랜잭션 자동 */ }
결론
- Tomcat은 “빈 엔진”, TomEE는 “Tomcat에 EE 기능을 얹은 풀스택 컨테이너”.
- EE 표준 기능(JTA/JPA/CDI/EJB 등)과 JNDI 네이밍 규칙이 가장 큰 차이이며, 여러분이 겪는 오류도 이 지점에서 발생했습니다.
- 현재 환경에서 TomEE를 쓰고 EE 리소스/JNDI를 활용 중이라면, openejb:Resource/... 또는 앱 로컬 java:comp/env/... 으로 이름을 정확히 맞추는 것이 핵심