본문 바로가기
교육, 학습/멀티캠퍼스_풀 스택

Servlet - 컨테이너 종료시까지 데이터 공유(ServletContext)

by 개발하는 경제학도 2022. 3. 16.

강의 소개

현재 수강하고 있는 멀티캠퍼스 k-digital 지능형 웹서비스 풀 스택 과정을 수강하며 적은 내용입니다.

교재로는 자바 웹을 다루는 기술을 사용하고 있습니다.


ServletContext 클래스

ServletContext클래스는 동일 web application 내부의 다른 파일과 데이터 공유를 하는 데 사용된다.

 

ServletContext클래스는 톰캣 컨테이너 실행 시 각 context(웹 앱플리케이션)마다 1개의 ServletContext 객체를 생성한다.

그리고 톰캣 컨테이너가 종료하면 그 객체는 소멸된다.

ServletContext객체는 웹 애플리케이션이 실행되면서 애플리케이션 전체의 공통 자원이나 정보를 미리 바인딩해서 서블릿들이 공유하여 사용한다.

 

특징

javax.servlet.ServletContext로 정의되어 있다.

서블릿과 컨테이너 간의 연동을 위해 사용된다.

context(웹 애플리케이션)마다 1개의 ServletContext 객체가 생성된다.

서블릿끼리 데이터를 공유하는 데 사용된다.

컨테이너 실행 시 생성되며 컨테이너가 종료되면 소멸된다.(따라서 톰캣을 종료하지 않았으면 브라우저를 닫았다가 다시 들어가도 정보 유지된다.)

 

제공 기능

서블릿에서 파일 접근 기능

자원 바인딩 기능

로그 파일 기능

context에서 제공하는 설정 정보 제공 기능

 

ServletContext의 메서드

getServletContext메서드를 이용해 ServletContext객체를 가져온다.

ServletContext context = getServletContext(); //현재서블릿 컨텍스트정보 객체

 setAttribute메서드를 이용해 해당 name으로 객체를 ServletContext에 바인딩한다.

context.setAttribute(String name, Object object); //현재 컨텍스트 내의 모든 파일과 공유. 서버 종료시까지

getAttribute메서드를 이용해 주어진 name 이용해 바인딩된 value를 가져온다.(name이 없으면 null반환) 

context.getAttribute(String name);

removeAttribute메서드를 이용해 해당 named으로 ServletContext에 바인딩된 객체를 제거한다.

 

context.removeAttribute(String name);

 

예시 코드

아래에는 서블릿에서 JDBC연결 시 같은 DB 연결 정보를 재사용할 수 있도록 공유하는 예시이다.

 

[DBSetServlet]

// ServletContext 객체로 현재 컨택스트내 모든 파일과 객체를 공유.
@WebServlet("/dbset")
public class DBSetServlet extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 1. 현재 서블릿 컨텍스트 정보 객체를 가져온다.
		ServletContext context = getServletContext();

		DBInform db = new DBInform();
		db.setDriverName("com.mysql.cj.jdbc.Driver");
		db.setJdbcUrl("jdbc:mysql://localhost:3306/접속할스키마이름");
		db.setAccount("DB계정ID");
		db.setPassword("DB계정PW");
		
		// 2. 현재 같은 컨텍스트 안에 있는 서블릿에 객체를 공유한다.(= servletContext 객체에 데이터를 바인딩)
		context.setAttribute("share_db", db);
		
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		out.println("<h1>db정보 공유했습니다</h1>");
	}

}

JDBC연동 시 driverName, jdbcUrl, account, password는 항상 같은 값이다. 따라서 이런 공통된 정보들을 재사용할 수 있도록 위 클래스에서 share_db라는 이름으로 공유한다.

 

[DBInform]

public class DBInform {
	// 같은 컨텍스트를 여러 서블릿이 동일 DB접속
	String driverName;
	String jdbcUrl;
	String account;
	String password;
	
	public String getDriverName() {
		return driverName;
	}
	public void setDriverName(String driverName) {
		this.driverName = driverName;
	}
	public String getJdbcUrl() {
		return jdbcUrl;
	}
	public void setJdbcUrl(String jdbcUrl) {
		this.jdbcUrl = jdbcUrl;
	}
	public String getAccount() {
		return account;
	}
	public void setAccount(String account) {
		this.account = account;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}	
}

setter, getter가 있는 클래스이다.

 

[DBGetServlet1]

// dbset으로부터 정보 공유받는 서블릿이다. dbset이 먼저 실행되어야 한다.
// 브라우저 종료한뒤 다시 들어가도 서버는 살아있으므로 정보전달받을 수 있다.
@WebServlet("/dbget1")
public class DBGetServlet1 extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 1. 현재 서블릿 컨텍스트 정보 객체를 가져온다.
		ServletContext context = getServletContext();
		// 2. share_db로 이전에 바인딩된 정보를 가져온다.
		DBInform db = (DBInform)context.getAttribute("share_db");
		
		try {
			Class.forName(db.getDriverName());
			Connection conn = DriverManager.getConnection(db.getJdbcUrl(), db.getAccount(), db.getPassword());
			PreparedStatement pt = conn.prepareStatement("select count(*) from member_table");
			ResultSet rs = pt.executeQuery();
			rs.next();
            
			response.setContentType("text/html;charset=utf-8");
			PrintWriter out = response.getWriter();
			out.println("<h1>db내에 " + rs.getInt("count(*)") + "개의 행 존재</h1>");

		}catch (Exception e) {
			e.printStackTrace();
		}	
	}
}

DBSetServlet에서 공유해준 share_db를 getAttribute메서드로 전달받는 클래스이다. 

 

[DBGetServlet2]

// dbset으로부터 정보 공유받는 서블릿이다. dbset이 먼저 실행되어야 한다.
// 브라우저 종료한뒤 다시 들어가도 서버는 살아있으므로 정보전달받을 수 있다.
@WebServlet("/dbget2")
public class DBGetServlet2 extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		// 1. 현재 서블릿 컨텍스트 정보 객체를 가져온다.
		ServletContext context = getServletContext();
		// 2. share_db로 이전에 바인딩된 정보를 가져온다.
		DBInform db = (DBInform)context.getAttribute("share_db");
		
		try {
			Class.forName(db.getDriverName());
			Connection conn = DriverManager.getConnection(db.getJdbcUrl(), db.getAccount(), db.getPassword());
			PreparedStatement pt = conn.prepareStatement("select avg(salary) from employees");
			ResultSet rs = pt.executeQuery();
			rs.next();
//			System.out.println(rs.getInt("count(*)"));
			
			response.setContentType("text/html;charset=utf-8");
			PrintWriter out = response.getWriter();
			out.println("<h1>db내에 급여 평균값 " + rs.getInt("avg(salary)") + "</h1>");

			// 서버 종료되지 않았더라도 사용 그만하기 위해 사용한다. getAttribute호출불가 상태가 된다. 
			context.removeAttribute("share_db");
			
		}catch (Exception e) {
			e.printStackTrace();
		}
		
	}

}

DBGetServlet1 클래스와 마찬가지로 공유된 jdbc 정보들을 받는다. 이렇듯 ServletContext객체를 사용하여 톰캣 컨테이너가 종료되지 않는 시점까지 여러 서블릿이 공유 데이터를 전달받을 수 있다.

댓글