JNDI와 커넥션풀, 커넥션풀 직접만들기
JNDI: JNDI는 자바 네이밍 디렉토리 인터페이스(Java Naming and Directory Interface)의 약자이다. 한 서비스가 다른 서비스를 탐색할 때 유용하게 사용한다.
저장되는 공간이 폴더 형태로 되어있고, 각 객체가 폴더 내에 저장된다. “저장된 개체의 주소값을 넘겨달라”가 룩업이다.
쉽게 생각하면 탐색기라고 할 수 있다. Context 새 개체를 만들고, comp/env에 접근한 뒤, 그 안에서 지정한 이름(jdbc/oracle)의 데이터 소스를 얻어온다. 그리고 나서 겟 커넥션을 하면 된다.
그 전에는 연결->사용->해제 였으나, 이제는 연결->사용-> “반환”으로 바뀐다.(커넥션풀)

커넥션풀 직접 만들기
여기서부터는 커넥션풀의 원리를 이해하기 위해 직접 만들어본다. 새로 만든 소스에 대한 설명은 노란색 표 안에 넣어두었다. 실제 커넥션풀 소스는 파란색 표 안에 넣어두었다.
(1) server.xml
서버에 대한 정보를 가지고 있는 xml파일. 오라클 드라이버 주소부터 커넥션풀 갯수까지 각종 서버정보를 기입해놓는다.
<?xml version=”1.0″ encoding=”UTF-8″?>
<context>
<Resource
name=”jdbc/oracle”
type=”com.sist.DataSource”
driverClassName=”oracle.jdbc.driver.OracleDriver”
url=”jdbc:oracle:thin:@localhost:1521:ORCL”
password=”tiger”
username=”scott”
maxActive=”10″
maxIdle=”5″
maxWait=”-1″
/>
</context>
|
설명> server는 xml파일로 저장된다. 여기서 Resource는 테이블에 해당된다. name, type, driverClassName, url, password, username, maxActive, maxIdle, maxWait은 컬럼에 해당된다. name은 “jdbc/oracle” type 은 DataSource로 한다. 기존의 커넥션풀을 쓰려면 type=”javax.sql.DataSource” 을 써야 한다. driverClassName 은 오라클 드라이버 이름을 넣는다. url 은 오라클 드라이버 주소를 넣는다. password는 오라클 패스워드 username은 오라클 아이디 maxActive는 커넥션 풀 최대갯수 maxIdle 커넥션 풀 유지갯수 maxWait -1이면 무한정 대기(1000이면 1초 대기) |
|
원래 코드> <Context docBase=”프로젝트이름” path=”/프로젝트이름” reloadable=”true” source=”org.eclipse.jst.jee.server:프로젝트이름”> |
(2) DataSource.java
서버.xml의 정보를 실제로 저장해두는 영역. 일종의 DTO라고 생각하면 쉽다.
import java.sql.Connection;
import java.sql.DriverManager;
public class DataSource {
private String driverClassName;
private String url;
private String username;
private String password;
private int maxActive;
private int maxIdle;
private int maxWait;
//이 아래로는 게터세터
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getMaxActive() {
return maxActive;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public int getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
public int getMaxWait() {
return maxWait;
}
public void setMaxWait(int maxWait) {
this.maxWait = maxWait;
}
}
|
설명> DataSource에는 커넥션에 필요한 기본적인 변수들을 넣어놓는다. 일단 필수적인 변수들로 private String driverClassName; 을 선언한다. 그리고 게터/세터를 적용한다. |
(3) MyHandler.java
마이 핸들러는 xml을 한 줄씩 읽어와 해시 맵에 저장하는 역할을 한다. 다시 말해, xml에서 get한 엘리먼트들을 데이터 소스에 넣어 맵으로 만드는 기능을 가졌다.
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.*;
public class MyHandler extends DefaultHandler {
Map map=new HashMap();
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
try {
if(qName.equals(“Resource”))
{
String name=attributes.getValue(“name”);
String type=attributes.getValue(“type”);
String driver=attributes.getValue(“driverClassName”);
String url=attributes.getValue(“url”);
String pwd=attributes.getValue(“password”);
String user=attributes.getValue(“username”);
String ma=attributes.getValue(“maxActive”);
String mi=attributes.getValue(“maxIdle”);
String mw=attributes.getValue(“maxWait”);
Class clsName=Class.forName(type);
DataSource ds=(DataSource)clsName.newInstance();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(user);
ds.setPassword(pwd);
ds.setMaxActive(Integer.parseInt(ma));
ds.setMaxWait(Integer.parseInt(mw));
ds.setMaxIdle(Integer.parseInt(mi));
map.put(name, ds);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
|
설명> (1)MyHandler는 DefaultHandler를 상속받는다. 그 후 해시 맵을 우선 선언한다. public class MyHandler extends DefaultHandler {
(2) startElement를 오버라이딩한다. startElement는 xml에서 한 줄을 읽어오는 역할이다. startElement는 한 줄이 시작하는 시점이다. 매개변수는 String uri, String localName, String qName, Attributes attributes가 있다. uri는 파일경로명. qName은 태그이름. 테이블에 해당하는 <>안의 단어이다. Attributes는 속성명. 컬럼에 해당하는 <>안의 단어이다. //한 줄이 시작하는 시점에 큐네임(태그이름)이 Resource라면 //변수에 어트리뷰트(속성명)기억해둔다. //데이터 소스를 선언하고, 데이터소스에 각 변수를 대입한다. //cf)데이터 소스를 선언할 때 type을 메모리 할당한 후 데이터소스로 변환해야 한다.** |
(4) Context.java
컨텍스트 클래스는 마이핸들러로 맵을 선언한다. (앞서, 마이핸들러는 get한 엘리먼트들을 데이터소스에 넣어 맵으로 만드는 기능이었다) 컨텍스트 클래스의 lookup 메소드는 키 이름(ex: “jdbc/oracle”)를 넘기면 맵(Object)를 반환해준다.
import java.util.*;
import java.io.*;
import javax.xml.parsers.SAXParserFactory;
import com.sun.org.apache.xerces.internal.parsers.SAXParser;
public class Context {
Map map=new HashMap();
public Context(){
try{
SAXParserFactory spf=SAXParserFactory.newInstance();
javax.xml.parsers.SAXParser sp=spf.newSAXParser();//SAXParser sp=spf.newSAXParser();
MyHandler mh=new MyHandler();
String path=”C:\\webDev2\\workspace\\JNDIProject\\src\\com\\sist\\server.xml”;
sp.parse(new File(path),mh);
map=mh.map;
}catch(Exception ex){}
}
public Object lookup(String name){
return map.get(name);
}
}
|
설명> Context 클래스: (2) 삭스 파서 팩토리(spf)를 선언 SAXParserFactory spf=SAXParserFactory.newInstance(); cf) String path=”C:\\webDev2\\workspace\\JNDIProject\\src\\com\\sist\\server.xml”; 설명> lookup 메소드: public object: 객체(Object)를 반환한다. 여기서 객체는 해쉬 맵이다. return map.get(name): 해쉬맵의 키 값에 따른 키를 가져온다. 예를 들면 “jdbc/oracle” 이라는 이름(키)의 맵을 반환한다. |
(5) MainClass
커메인 클래스는 직접 만드는 커넥션 풀에만 존재하고, 실제 커넥션 풀에는 존재하지 않는다.
실제 커넥션 풀에는 getConnection()이라는 이름의 메소드를 만들면 된다.
import java.sql.*;
public class MainClass {
public static void main(String[] args) {
try{
Context c=new Context();
DataSource ds=(DataSource)c.lookup(“jdbc/oracle”);
Connection conn=ds.getConnection();
System.out.println(ds.getUrl());
System.out.println(ds.getDriverClassName());
System.out.println(ds.getPassword());
System.out.println(ds.getUsername());
}
catch(Exception ex){System.out.println(ex.getMessage());}
}
}
|
설명> (1) Context를 새로 선언한다. (2) ‘데이터 소스’에 해시맵을 넣는다. ‘컨텍스트.룩업‘은 name에 대한 해시 맵을 반환해주는 메소드다. (3) ‘데이터 소스.겟커넥션‘으로 연결한다. |
|
원래 소스> public void getConnection(){ |
.