서블릿 3.0 이상을 사용하는 스프링 프레임워크에서 가능한 기능이다.
WebListener이라는 어노테이션을 사용해서 쉽게 터널링을 할 수 있다.
기본 MariaDB, Mysql, Oracle 또는 Mongodb등 어떠한 데이터베이스에 접속하던지 간에 해당 어노테이션을 잘 활용하면 같은 모양으로 터널링이 가능하다.
서블릿 3.0 이상이 지원되는 환경을 구성하는게 가장 중요하다.
WebListener는 스프링에서 정의한 Listener의 종류이다.
스프링에서 정의한 웹 어플리케이션 구조를 먼저 살펴보면,
여기서 리스너의 1번 개념을 적용해서 공통적으로 데이터베이스에 대한 터널링이 가능 하다.
<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
<!-- SSH 포트연결 라이브러리 -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<!-- @WebListener 사용하기 위한 라이브러리 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
이것들을 pom.xml에 우선 추가를 해준뒤에 클래스를 하나 생성하는데 그 클래스에서는
ServletContextListener를 implements 해준다.
ServletContextListener란?
- 웹 어플리케이션이 시작되거나 종료될 때 호출할 메서드를 정의한 인터페이스.
- public void contextInitialized(ServletContextEvent sce) : 웹어플리케이션을 초기화할 때 호출
- public void contextDestroyed(ServletContextEvent sce) : 웹 어플리케이션을 종료할 때 호출.
생성한 클래스에 @WebListener 어노테이션을 붙여주고 ServletContextListener 인터페이스를 상속받는다.
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class DataBaseListener implements ServletContextListener{
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
@Override
public void contextInitialized(ServletContextEvent sce) {
}
}
이렇게 생성하게되면 ServletContext가 생성될때 해당내용이 수행된다.
아래의 방법이 터널링하는 방법이다.
처음에 pom.xml에 등록한 JSCH를 활용하여 ssh 접속을 설정한다.
SSH 연결 클래스
import java.util.Properties
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class SSHConnector {
private final static String remoteHost = "192.168.0.1";
private final static String user = "admin";
private final static String password = "admin";
private final static int port = 1234;
private Session session;
public void closeSSH() {
session.disconnect();
}
public SSHConnector() {
try {
JSch jSch = new JSch();
session = jSch.getSession(user, remoteHost, port);
session.setPassword(password);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
session.setPortForwardingL(port, remoteHost, 3306);
System.out.println("연결성공");
}catch (Exception e){
e.printStackTrace();
}
}
}
SSH연결 구현 클래스
@WebListener
public class SSHContextListener implements ServletContextListener {
private SSHConnector sshConnector;
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("시작!");
try {
sshConnector = new SSHConnector();
System.out.println("끝!");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("끝!");
sshConnector.closeSSH();
}
}
먼저 첫번째 포트번호는 ssh로 접속할 포트번호이다
그리고 가상포트는 말 그대로 가상포트, 아무숫자나 써 주어도 상관없는 포트이다.
-> 데이터베이스 서버에서 충돌나지 않도록 주의!!
사용할데이터베이스포트 는 mysql, oracle 또는 몽고db가 열어준 포트를 의미한다.
실제 데이터베이스에서 사용중인 포트가 3306이라고 하자.
그리고 가상포트를 1234라고 가정을 한다.
만약 1234로 접속을 시도하는 행위를 발견하면 알아서 스스로 127.0.0.1:3306 으로 접속 행위를 돌려준다.
여기까지 하였다면 내가 접속할 Mysql, 오라클, 몽고db의 접속 주소를 아래처럼 바꾸어 주어야 한다.
기존 접속방식은 그대로두고 접속할 아이피와 포트만 바꾸면 된다.
mybatis-config.xml
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close" >
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:1234/databaseName" />
<property name="username" value="username" />
<property name="password" value="password" />
<property name="validationQuery" value="SELECT 1 FROM DUAL" />
<property name="testWhileIdle" value="true" />
</bean>
이렇게 한다면 1234를 요청하는데 위에서 설정해준 터널링 처리로 인해 SSH포트를 연결한 3306의 mysql에서 데이터를 가져와서 데이터를 뿌려주게 된다.
web.xml에서 사용할 경우
<listener>
<listener-class>SSHContextListener클래스의 경로</listener-class>
</listener>