Java EE 정리 02
26 Feb 2019
Reading time ~5 minutes
Java EE 정리 02 - Servlet 요청처리, Servlet Life Cycle, Class Life Cycle Servlet 호출
Servlet 요청처리(전체 흐름)
- HDD에 Web 서비스할 폴더를 등록한다.(server.xml)
- Source Code(Servlet) 작성
- DD(Deployement Descriptor, web.xml)에 작성한 Servlet을 기술(Servlet Mapping)
- 요청 대기
- 클라이언트가 웹 브라우저를 통해 요청
- 요청한 URL을 웹컨테이너가 분석
- 응답
- 웹 브라우저가 HTML을 응답받아 화면에 그림
Servlet 요청 처리(네트워크 관점)
- 서버 포트 열기
- 서비스되는 폴더를 Mapping(server.xml)
- DD Loading(web.xml)
- 대기
- 웹브라우저 실행
- URL 입력
- 접속자가 접속하면서 생성된 Socket으로부터 RequestFacade, ResponseFacade가 생성
- 요청을 처리하는 서블릿 객체 생성
- 요청 방식(GET/POST)에 맞는 method 호출
- 요청 방식에 맞는 doGet 또는 doPost 호출
- HttpServletResponse 객체 변수를 이용 MIME Type 설정
- ResponseFacade로부터 스트림을 얻음
- 얻은 스트림에 응답내용을 누적
- HTML을 응답
- 클라이언트는 응답받은 HTML을 웹브라우저 그림
Servlet Life Cycle
- 객체의 생성, 사용, 소멸 단계
- Lifecycle은 Container가 관리
-
GenericServlet이 Lifecycle에 대한 method를 제공
-
init()
- 생성자의 역할을 하는 method
- 최초 접속자에 의해서 1번 호출됨
- 객체생성 시 초기화되어야할 값을 설정하거나 실행되어야할 코드를 정의
-
service, doGet, doPost
- 업무처리(요청, 응답처리)
- 접속자에게 보여줄 페이지 생성
- 접속한 접속자 수대로 수행
-
destroy()
- 객체가 소멸될 때 호출되는 method
-
Web Container Instance가 사라질 때 호출됨
- 접속자가 연결을 끊는다고 호출되는게 아님!
- 가장 마지막에 1번 호출됨
-
init()
- 첫번째 접속하는 사람은 요청한 서블릿 객체를 생성되고 응답받기 때문에 가장 느리다.
- 두번째 접속하는 사람은 서블릿 객체가 객체가 생성되어 있기 때문에 빠르게 응답을 받는다.
-
Servlet Life Cycle 예
- 콘솔창에서 Terminate로 서버를 종료시키면 비정상 종료이므로 destroy()가 불리지 않음
- Server 탭에서 Stop으로 서버를 정상 종료시키면 destroy()가 호출됨
- 콘솔창에서 Terminate로 서버를 종료시키면 비정상 종료이므로 destroy()가 불리지 않음
// 1. HttpServlet 상속
@SuppressWarnings("serial")
public class LifeCycle extends HttpServlet {
// 생명주기 method
public void init() {
System.out.println("===> init method : 최초 접속자에 의해 1번 호출(생성자 역할) ");
}
public void destroy() {
System.out.println("===> destroy method : Web Container가 종료될 때 객체가 사라지면서 1번 호출");
}
// 2. 응답방식에 대한 처리 method를 Override
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 3. 응답방식 설정(MIME-TYPE 설정)
resp.setContentType("text/html;charset=UTF-8");
// 4. 출력스트림 얻기
PrintWriter out = resp.getWriter();
// 5. 응답내용 생성
out.println("<strong>방문자 정보</strong><br/>");
out.print("<strong>접속자 ip : </strong>");
out.print(req.getRemoteAddr());
out.println("에서 접속하셨습니다.");
out.flush();
System.out.println("---> service, doGet, doPost : 모든 접속자에게 호출. 여러번 호출 "+req.getRemoteAddr());
}
}
Class Life Cycle
-
생성->method->소멸
- 생성 - 생성자
- method - 정의한 method
- 소멸 - Object.finalize()
- C에서는 개발자가 직접 소멸자를 사용해서 소멸시킴
-
Java에서는 Gabage Collector(GC)가 heap에 생성된 객체를 소멸시킴
-
GC가 소멸시키는 기준
- 참조되지 않는 객체
- 일정기간 사용하지 않아 앞으로도 사용될 확률이 없는 객체
- 자동동작(언제 동작하는지는 알 수 없음)
-
개발자가 호출가능(System.gc())
- GC가 동작하면 시스템에 부하가 걸린다.
- 직접 호출은 비권장
-
GC가 소멸시키는 기준
- finalize() 예
public class Person {
private String name;
public Person(String name) {
this.name = name;
System.out.println("신입사원 "+name+"님 입사하셨습니다.");
}
@Override
protected void finalize() throws Throwable { // GC에 의해 객체가 소멸될 때 호출된다.
System.out.println(name+"님이 퇴사하셨습니다.");
}
public String getName() {
return name;
}
}
/**
* Garbage Collector를 호출하여 객체를 소멸시키기
* (메모리의 여유공간 확보)
* 이재현 사원의 모함으로 다른 사원들은 모두 짤려버림
* @author owner
*/
public class UseGarbageCollector {
public static void main(String[] args) {
Person p = new Person("이재찬");
p = new Person("김정윤");
p = new Person("정택성");
p = new Person("공선의");
p = new Person("이재현");
System.gc(); // GC 호출
System.out.println("남은 사원 : "+p.getName());
}
}
Servlet 호출
-
GET방식
- doGet method에서 업무처리
<!-- 링크 호출 -> GET -->
<a href="서블릿 url-mapping명">
// JavaScript 호출 -> GET
location.href="서블릿 url-mapping명";
<!-- form 호출 -> GET, method 생략하면 기본이 GET방식 -->
<form method="get" action="서블릿 url-mapping명">
...
<input type="submit">
</form>
-
POST방식
- doPost method에서 업무처리
<!-- POST방식은 form 호출 방식만 가능 -->
<form method="post" action="서블릿 url-mapping명">
....
<input type="submit">
</form>
GET/POST 방식 Servlet 호출 예
- TestCall.java(Servlet)
// 1. HttpServlet 상속
@SuppressWarnings("serial")
public class TestCall extends HttpServlet {
// 2. 요청방식을 처리할 수 있는 method Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 3. 응답방식 설정
response.setContentType("text/html;charset=UTF-8");
// 4. 출력스트림 얻기
PrintWriter out = response.getWriter();
// 5. 출력 내용 생성
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>GET 방식의 요청처리</title>");
out.println("<style type='text/css'>");
out.println("span { font-weight:bold; font-size:20px; color:#0000FF } ");
out.println("</style>");
out.println("</head>");
out.println("<body>");
out.println("<span>GET방식 요청처리</span><br/>");
out.println("<a href='date0226/call_servlet.html'>뒤로</a>");
out.println("</body>");
out.println("</html>");
}
// 2. 요청방식을 처리할 수 있는 method Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 3. 응답방식 설정
response.setContentType("text/html;charset=UTF-8");
// 4. 출력스트림 얻기
PrintWriter out = response.getWriter();
// 5. 출력 내용 생성
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>POST 방식의 요청처리</title>");
out.println("<style type='text/css'>");
out.println("span { font-weight:bold; font-size:15px; color:#FF0000 } ");
out.println("</style>");
out.println("</head>");
out.println("<body>");
out.println("<span>POST방식 요청처리</span><br/>");
out.println("<a href='javascript:history.back()'>뒤로</a>");
out.println("</body>");
out.println("</html>");
}
}
- call_servlet.html
<body>
<div id="wrap">
<!--
서블릿 요청 URL : http://localhost:8080/servlet_prj/test_call
HTML 요청 URL : http://localhost:8080/servlet_prj/date0226/call_servlet.html
-->
<div id="get">
<strong>GET방식 요청</strong>
<div>
<ul>
<li><a>태그 : <a href="../test_call">요청</a></li>
<li>
location.href 요청 : <a href="#void" class="link">JavaScript 요청</a>
<input type="button" value="JavaScript 요청" class="btn" id="btnJSGet">
</li>
<li>
<!-- JavaScript에서 method와 action을 설정하여 이동 -->
<form name="getFrm">
<input type="submit" value="get 요청" class="btn" id="btnGet"/>
</form>
</li>
</ul>
</div>
</div>
<div id="post">
<strong>POST방식 요청</strong>
<div>
<form action="../test_call" method="post" id="postFrm">
<input type="button" value="post 요청" class="btn" id="btnPost"/>
</form>
</div>
</div>
</div>
</body>
#wrap {
width: 500px;
height: 400px;
margin:0px auto;
}
#get {
width: 220px;
height: 150px;
border: 1px solid #333;
border-radius: 10px;
box-shadow: 10px 10px 10px #333;
float: left;
padding-top:10px;
padding-left:5px;
}
#post {
width: 220px;
height: 150px;
border: 1px solid #333;
border-radius: 10px;
box-shadow: 10px 10px 10px #333;
float: right;
padding-top:10px;
padding-left:5px;
}
$(document).ready(function() {
$(".link").click(function() {
movePage();
});
$("#btnJSGet").click(function() {
movePage();
});
$("#btnGet").click(function() {
// JavaScript에서 action과 method를 변경
// JavaScript로 속성 변경
var obj = document.getFrm;
// method 변경 : obj.method="변경할 method";
// action 변경 : obj.action = "변경할 action"
obj.method="get";
obj.action="../test_call";
/*// jQuery로 속성변경
var obj = $("[name='getFrm']");
obj.prop("method","get");
obj.prop("action","../test_call"); */
obj.submit();
});
$("#btnPost").click(function() {
$("#postFrm").submit();
});
});
function movePage() {
if(confirm("이동하시겠습니까?")) {
// location.href="../test_call"; // 뒤로가기 가능
location.replace("../test_call");
}
}