환경 정보
IntelliJ IDEA 2019.3 Ultimate, Amazon Corretto 11, Tomcat 9, JDBC 4.2, 의존성 관리 환경 X
Tomcat 서버 DataSource 설정 방법 (+JNDI)
❕ 포스트 상단에는 DataSource, JNDI의 이론적인 내용이 포함되어 있으므로 바로 설정, 적용 방법을 보려면 스크롤을 밑으로 내려 'DataSource 적용'부터 보면 됩니다.
DataSource는 JDK 1.4부터 포함된 javax.sql 패키지의 API이다. DataSource를 이용하여 Java EE 서버(예: 톰캣 서버)에서 DB 커넥션 풀을 관리할 수 있다.
javax.sql 패키지
javax.sql 패키지는 java.sql 패키지의 기능을 보조하기 위해 만들어진 확장 패키지이다.
서버 쪽 데이터 소스에 대한 접근을 쉽게 하고 더 다양한 방법으로 데이터를 다룰 수 있는 API를 제공한다.
JDK 1.4부터 포함되었고 Java EE에서 기본 패키지로 정의되어 있다.
📝 javax.sql 패키지 주요 기능
✔ DriverManager를 대체할 수 있는 DataSource 인터페이스 제공
✔ Connection, Statement 객체의 Pooling
✔ 분산 트랜잭션 관리
✔ Rowsets 지원
DataSource
DataSource는 DriverManager를 통해 DB 커넥션을 얻는 것 보다 더 좋은 기법을 제공한다.
✔ 첫째, DataSource는 서버에서 관리하기 때문에 DB나 JDBC 드라이버가 변경이 수월하다.
DriverManager를 사용하면 웹 어플리케이션에서 관리하기 때문에 DB 접속 정보나 JDBC 드라이버가 변경될 경우 웹 어플리케이션의 코드도 변경해야하기 때문이다.
✔ 둘째, Connection, Statement 객체를 pooling할 수 있으며 분산 트랜잭션을 다룰 수 있다. 즉 DataSource는 자체적으로 Connection Pool 기능을 구현한다. DriverManager를 사용할 경우 Connection Pool 기능을 별도로 개발하고 관리해야한다.
📝 DataSource의 Connection
DataSource가 반환하는 Connection 객체는 DriverManager의 Connection 객체를 한번 더 감싼 형태이다.
DAO가 DataSource에게 Connection을 달라고 요청하면 DataSource는 Connection 대행 객체(Proxy Object)를 반환한다. Apache DBCP 컴포넌트의 경우 대행 객체인 PoolableConnection을 반환한다.
PoolableConnection 객체는 Connection 인터페이스를 구현하였으며 실제 Connection을 가리키는 참조 변수(_conn)와 connection pool을 가리키는 참조 변수(_pool)가 들어있다. 그래서 요청이 들어오면 PoolableConnection이 직접 처리하는게 아니라 실제 Connection에게 처리를 위임한다.
따라서 DataSource가 반환한 Connection 객체에 close()를 호출하면 PoolableConnection은 실제 Connection 객체를 connection pool에 반환한다. 즉 실제로 Connection 객체가 닫히는게 아니라 재사용할수 있도록 pool에 반납되는 것이다.
JNDI(Java Naming and Directory Interface API)
디렉터리 서비스에 접근하는데 사용하는 API
어플리케이션은 JNDI를 사용하여 서버의 resource를 찾는다.
특히 JDBC resource를 data source라고 부른다.
Resource를 서버에 등록할 때 고유한 JNDI 이름을 붙이는데, JNDI 이름은 디렉터리 경로 형태를 가진다.
예를 들어 data source의 JNDI 이름은 'jdbc/mydb' 형식으로 짓는다.
다음은 Java EE 서버에서 자원을 찾을때의 기본 JNDI 이름이다.
JNDI 이름 | 설명 |
java:comp/env | 응용 프로그램 환경 항목 |
java:comp/env/jdbc | JDBC Data Source |
java:comp/ejb | EJB 컴포넌트 |
java:comp/UserTransaction | UserTransaction 객체 |
java:comp/env/mail | JavaMail 연결 객체 |
java:comp/env/url | URL 정보 |
java:comp/env/jms | JMS 연결 객체 |
따라서 서버에서 'jdbc/mydb'라는 data source를 찾으려면 'java:comp/env/jdbc/mydb'라는 JNDI 이름으로 찾아야 한다. 즉 lookup() 메소드에 'java:comp/env/jdbc/mydb'를 인자값으로 넘긴다.
lookup() 메소드는 InitialContext 클래스의 메소드로 JNDI 인터페이스를 통해 서버에 등록된 객체를 찾는다.
DataSource 적용
1. DataSource 구현체 준비
JDBC를 사용하려면 JDBC 구현체 = JDBC 드라이버가 필요하듯이 DataSource를 사용하려면 javax.sql 패키지 구현체가 필요하다.
http://commons.apache.org/ 에 접속한다.

'Components' 클릭

'DBCP' 클릭

'Downloads' 클릭

'commons-dbcp2-2.7.0-bin.zip'을 클릭하여 다운로드받는다.
commons-dbcp2-2.7.0-bin

commons-dbcp2-2.7.0.jar 파일을 프로젝트 lib 디렉토리에 복사해둔다.
DBCP 컴포넌트는 내부적으로 Pool, Logging 컴포넌트를 사용하기 때문에 해당 라이브러리도 다운로드 받아야 한다.

DBCP를 다운받은 것과 동일하게 Apache Commons 사이트의 Components 목록에서 Logging, Pool 링크를 클릭해서 다운로드 받는다.
commons-pool2-2.8.0

commons-logging-1.2

Pool, Logging jar파일도 마찬가지로 프로젝트 lib 디렉토리에 복사해둔다.

이렇게 총 3개의 jar파일 - commons-dbcp.jar, commons-pool.jar, commons-logging.jar 을 준비해 둔다.

Project Structure - Dependencies에 다운받은 jar파일을 추가해준다.
2. 톰캣 서버에 DataSource 설정
다음은 톰캣 실행 환경에서 DataSource를 설정하는 방법이다. 서버에 따라 설정 방법이 다르니 다른 서버를 사용할 경우 해당 제품의 문서를 참고하자.
프로젝트(모듈)의 context.xml에 다음과 같이 설정한다.
프로젝트별 context descriptor 파일을 추가하지 않았을 경우 이 포스트를 참고해서 추가한다.
context.xml
1
2
3
4
5
6
7
8
9
10
|
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Resource name="jdbc/knou" auth="Container" type="javax.sql.DataSource"
maxActive="10" maxIdle="3" maxWait="10000"
username="butterfield" password="1234"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3307/knou"
closeMethod="close" />
</Context>
|
cs |
📝 context.xml
Tomcat에 Web application container를 적재할 때, context를 참고한다. 일반적으로 Tomcat은 context.xml을 다음과 같은 순서로 찾아서 Web application container에 적용한다.
① server.xml <Context.xml> 참조 - 권장하지 않음
② CATALINA_HOME/conf/ENGINE_NAME/HOST_NAME/CONTEXT_PATH.xml 참조
<Host>의 속성에 xmlBase 값이 설정되지 않은 경우, 위 위치에 해당하는 file을 참조하게 됩니다. <Engine>의 name속성이 “Catalina“, <Host>의 name속성이 “localhost”이면 WebApp01의 context 설정 file의 위치는 “CATALINA_HOME/conf/Catalina/localhost/WebApp01.xml“이 된다.
③ Web application WAR, directory의 /META-INF/context.xml을 참조한다.
④ CATALINA_HOME/conf/context.xml 참조 - 다른 context file이 없는 경우
(참고 : https://daitso.kbhub.co.kr/61344/)
<WatchedResource> 태그
<WatchedResource>에 설정한 file의 변경이 있을 다시 로드한다.
<Resource> 태그
이 태그에 JNDI가 web.xml의 <resource-ref>와 <resource-env-ref> 요소를 조회(lookup)할 수 있게 반환할 resource를 선언한다.
속성명 | 설명 |
name | JNDI 이름 Context의 lookup()을 사용하여 자원을 찾을때 사용한다. java:comp/env 디렉터리에서 찾을 수 있다. |
auth | 자원 관리의 주체를 지정한다. Application / Container를 지정할 수 있다. |
type | Resource의 타입을 패키지 이름을 포함한 클래스 이름(QName)을 지정한다. |
driverClassName | JDBC 드라이버 클래스의 이름 패키지 이름을 포함한 클래스 이름(QName)을 지정한다. |
url | DB 커넥션 URL |
username | DB 사용자 이름 |
password | DB 암호 |
maxActive | DataSource로부터 꺼낼 수 있는 커넥션 최대 개수 기본값 : 8개 |
maxIdle | DataSource에서 유지할 수 있는 사용되지 않는 커넥션의 최대 개수 최대 유지 개수를 넘어서 반납되는 커넥션은 close된다. 기본값 : 8개 |
maxWait | 발급한 커넥션 수가 최대값인 상태에서 추가로 커넥션 발급 요청이 들어왔을때 커넥션을 준비하기 위해 반납을 기다리는 최대 밀리초 최대 밀리초가 지날때까지 반납되는 커넥션이 없으면 Exception을 던진다. 기본값 : -1 (커넥션 반납할때까지 기다림) |
closeMethod | 톰캣 서버가 종료될 때 자원을 해제하기 위해 호출하는 메소드명 매개변수가 없어야 한다. 톰캣 서버는 내부적으로 DataSource를 생성할때 아파치 DBCP의 BasicDataSource 구현체를 사용하며 BasicDataSource의 자원 해제 메소드는 close()이다. |
3. web.xml 설정
context.xml에 선언한 DataSource를 웹 어플리케이션에서 사용하려면 web.xml에 해당 resource를 참조한다는 선언을 해야한다.
web.xml의 <web-app> 태그 안에 다음 항목을 추가한다.
web.xml
1
2
3
4
5
6
|
<!-- 서버 자원 참조 선언 -->
<resource-ref>
<res-ref-name>jdbc/knou</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
|
cs |
각 태그는 다음을 의미한다.
태그 | 설명 |
<res-ref-name> | JNDI 이름 context.xml에 선언한 resource의 이름을 지정한다. |
<res-type> | 톰캣 서버에서 리턴하는 resource의 클래스 이름(패키지명 포함) context.xml에 선언한 type과 같아야 한다. |
<res-auth> | 자원 관리 주체 Container : 서버에서 관리함을 의미 |
4. InitialContext 객체를 사용해서 DataSource 얻기
아래와 같이 data source를 얻을 수 있다.
선언한 data source를 얻기 위해 InitialContext 객체를 생성하고 lookup() 메소드에 JNDI 이름 "java:comp/env/jdbc/knou" 를 넘겨 해당하는 resource를 반환받는다.
1
2
3
4
5
6
7
8
|
// 톰캣 서버에서 자원을 찾기 위해 InitialContext 인스턴스 생성
InitialContext initialContext = new InitialContext();
// lookup() 메소드로 JNDI 이름으로 등록돼있는 서버 자원 찾음
// @name : 서버 자원의 JNDI 이름
// 찾으려는 자원이 JDBC DataSource이므로 java:comp/env...
DataSource ds = (DataSource) initialContext.lookup(
"java:comp/env/jdbc/knou"
);
|
cs |
References
열혈강의 자바 웹 개발 워크북(프리렉, 2016, 엄진영)
'Java·Servlet·JSP' 카테고리의 다른 글
JAVA 웹 프로젝트에서 Properties 파일 활용하기 (0) | 2020.02.20 |
---|---|
리플랙션 API를 이용한 Front Controller 자동화 (0) | 2020.02.20 |
ServletContextListener로 DB 커넥션, DAO 공유 객체 관리하기 (0) | 2020.02.15 |
[IntelliJ] 회원가입 예제(MVC) - (7) DAO 분리하기 (0) | 2020.02.15 |
[JSP] JSTL 활용 방법 - JSP에서 자바 코드 제거 (0) | 2020.02.15 |
댓글