프로젝트 개요 및 목표
기존 JSP/Servlet 기반의 웹 애플리케이션에 Spring Context를 통합하고, 커넥션 풀 및 JdbcTemplate을 활용하여 데이터 접근 계층을 재구성하는 과정을 설명합니다. 본 가이드는 의존성 주입(DI) 패턴 적용, 선언적 트랜잭션 관리, 그리고 테스트 컨텍스트 초기화에 중점을 둡니다.
1. Maven 의존성 구성
Spring Core, JDBC 지원, Apache DBCP2 커넥션 풀, 그리고 테스트 유틸리티를 포함한 필수 라이브러리를 pom.xml에 정의합니다.
<dependencies>
<!-- Spring WebMVC 및 Core Context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.25</version>
</dependency>
<!-- Spring JDBC 및 트랜잭션 지원 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.25</version>
</dependency>
<!-- Apache Commons DBCP2 커넥션 풀 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
<!-- Lombok (보일러플레이트 코드 축소) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>
<!-- Spring Test Context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.25</version>
<scope>test</scope>
</dependency>
</dependencies>
2. 서비스 계층 및 의존성 주입 설계
데이터 접근 객체(DAO)를 서비스 계층에서 직접 인스턴스화하는 방식을 제거하고, Setter 메서드를 통해 외부에서 주입받도록 구조를 변경합니다.
public class MemberServiceImp implements MemberService {
private MemberRepository memberRepo;
// Spring 컨테이너가 의존성을 주입할 때 호출
public void injectMemberRepository(MemberRepository repository) {
this.memberRepo = repository;
}
@Override
public void executeMemberRegistration() {
memberRepo.insert();
}
}
3. Spring XML 설정 및 트랜잭션 관리
applicationContext.xml에서 컴포넌트 스캔 범위, DBCP2 데이터소스, 그리고 트랜잭션 매니저를 명시합니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 서비스 레이어 자동 스캔 -->
<context:component-scan base-package="kr.example.app.service" />
<!-- DBCP2 기반 데이터소스 빈 등록 -->
<bean id="primaryDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/demo_db" />
<property name="username" value="admin" />
<property name="password" value="secure_pass" />
<property name="initialSize" value="5" />
<property name="maxTotal" value="20" />
</bean>
<!-- JDBC 트랜잭션 관리자 설정 -->
<bean id="dbTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="primaryDataSource" />
</bean>
<!-- 어노테이션 기반 트랜잭션 활성화 -->
<tx:annotation-driven transaction-manager="dbTransactionManager" />
</beans>
4. 서블릿 컨테이너와의 연동
Tomcat 구동 시 Spring Root Context가 함께 초기화되도록 web.xml에 리스너를 등록합니다.
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="3.1">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>legacyController</servlet-name>
<servlet-class>kr.example.app.web.MainServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>legacyController</servlet-name>
<url-pattern>/process/*</url-pattern>
</servlet-mapping>
</web-app>
5. 컨텍스트 조회 및 실행 검증
기존 Servlet 또는 JSP 내에서 Spring이 관리하는 Bean을 안전하게 참조하려면 WebApplicationContextUtils를 활용합니다.
WebApplicationContext springCtx = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
MemberService svc = springCtx.getBean("memberServiceImp", MemberService.class);
svc.executeMemberRegistration();
서버 기동 후 요청을 처리하면, Spring 컨테이너가 자동으로 DAO 인스턴스를 주입하고 JdbcTemplate을 통해 쿼리를 실행합니다. 단위 테스트 환경에서는 @RunWith(SpringJUnit4ClassRunner.class)와 @ContextConfiguration을 결합하여 웹 컨테이너 의존성 없이 서비스 로직 및 트랜잭션 롤백 여부를 검증할 수 있습니다.