[Study-NextStep] 2021-12-11

일시 : 2021-12-11
범위 : 자바 웹 프로그래밍 Next Step 7장 실습(p225-p243)

Realize

ServletContextListener

ServletContextListener에 대한 초기화는 서블릿 초기화보다 먼저 진행된다.
서블릿의 초기화가 해당 서블릿과 관련한 초기화를 담당한다면, ServletContextListener 초기화는 웹 애플리케이션 전체에 영향을 미치는 초기화가 필요한 경우 활용할 수 있다.
(p228 내용)

Share

@WebListener

@WebListener란 servlet-api 라이브러리를 가져와서 사용할 수 있는 애노테이션으로, 클래스 위에 @WebListener를 붙임으로써 톰캣서버에게 Listener 클래스임을 알려준다.
web.xml의 listener와 동일한 역할을 하며, web.xml에 등록하지 않고 자동으로 실행시킬 수 있다.
(출처 : https://hoonys91.tistory.com/358)

Listener Class

리스너는 단어의 뜻으로 보자면 (소리를) 듣는 사람, 청취자다.
프로그래밍에서의 리스너는 무언가 소리를 듣는 사람을 뜻하기 보다는 특정 이벤트(특정한 사건)가 발생하기를 '귀 기울여' 기다리다가 실행되는 컴포넌트(메서드나 함수)를 말한다.

리스너는 이벤트가 발생함과 동시에 특정 행동을(메서드나 함수를 실행)하는데, 이것을 이벤트 핸들링이라고 합니다. 따라서 리스너를 이벤트 핸들러라고 부르기도 한다.

여기서 이벤트라는 말이 등장하는데, 이벤트는 발생한 특정 사건이나 일을 말하는데, 예를 들어보자면 마우스 클릭, 키보드 키 입력, 버튼 클릭, 텍스트 입력 등이 있다.

책에서 사용한 Listener는 ServletContextListener이며, 해당 Listener의 내용은 아래와 같다.

(출처 : https://dololak.tistory.com/616)

예외처리

예외에는 Checked Exception과 Unchecked Exception(Runtime Exception)이 있다.

예외를 처리하는 방법은 총 3가지다.

Try-catch (예외 복구)

예외가 발생하더라도 애플리케이션이 정상적인 흐름으로 진행되도록 처리하고 싶을 때 사용

Throws (예외처리 회피)

호출한쪽으로 예외를 던지고 회피한다.
하지만, 호출한 쪽에서 다시 예외를 받아 처리 하도록 하거나 해당 메소드에서 이 예외를 던지는 것이 최선의 방법이라는 확신이 있을때만 사용해야 한다.

만약 예외 발생하는 API들이 모두 try-catch로 처리한다면 API를 사용하는 애플리케이션에서 어떤 문제가 발생했는지 알 수 없게 된다. 따라서, API의 경우 Throws를 많이 사용하며 호출한 애플리케이션에 예외를 전달함으로써 예외 처리를 강요할 수 있고, 애플리케이션에서 예외 상황에 대한 적절한 처리가 가능해진다.

예외를 한 곳으로 모아서 한꺼번에 예외 처리를 하고 싶은 경우에도 사용한다.

Throw (예외 전환)

예외를 잡아서 다른 예외를 던지는 것이며, 호출한 쪽에서 예외를 받아서 처리할 때 좀더 명확하게 인지할 수 있도록 돕기 위한 방법이다.
(출처 : https://www.nextree.co.kr/p3239)

정적/동적쿼리 (Statement, PreparedStatement)

쿼리문은 아래의 수순으로 진행된다.

① 애플리케이션은 SQL문의 틀을 만들고 이를 DBMS로 보낸다. 특정값은 지정하지 않은 채로 남겨진다

INSERT INTO products (name, age) VALUES (?, ?);

② DBMS는 SQL문의 틀을 컴파일하며(최적화 및 변환), 실행하지 않은 상태로 결과만 저장한다.
③ 애플리케이션이 SQL문 틀의 변수에 값(바인드)을 지정하면 DBMS는 (결과를 반환할 수도 있는) SQL문을 실행한다.

Statement (정적 쿼리)

정적 쿼리는 실행할 때마다 매번 3단계를 거친다.
따라서, 캐싱이 의미 없는 Dynamic 쿼리일 때 사용한다.

Prepared Statement (동적 쿼리)

동적 쿼리는 처음 실행할 때만 3단계를 거친후 캐시에 담아 재사용한다.
따라서, SQL 문을 반복해서 사용할 때 사용할 때 사용한다.

이처럼 동적/정적 쿼리의 가장 큰 차이는 캐시 사용 여부이다.
(출처 : https://webstone.tistory.com/56)

리팩토링 종류

Extract Method

어떤 코드를 그룹으로 묶어도 된다고 판단이 들면, 해당 코드들을 빼내어 목적을 잘 나타내는 메서드로 만드는 메서드 추출 리팩토링
(참고 : IntelliJ에서의 단축키는 Commed+Option+M)

수정 전

public void printOwing(double previousAmount) {
  System.out.println("****************");
  System.out.println("*****고객 외상****");
  System.out.println("****************"); 
  
  double outstanding = previousAmount * 1.2; 
  
  for (Order o : orders) { 
  	outstanding += o.getAmount(); 
  } 
  
  System.out.println("name: " + name); 
  System.out.println("amount: " + amount); 
}

수정 후

public void printOwing(double previousAmount) { 
	printBanner(); 
	double outstanding = getOutstanding(previousAmount * 1.2); 
	printDetails(amout); 
} 

private void printBanner() { 
	System.out.println("****************"); 
	System.out.println("*****고객 외상****"); 
	System.out.println("****************"); 
} 

private double getOutstanding(double initialValue) {
	double result = initialValue; 
	for (Order o : orders) { 
		result += o.getAmount(); 
	} 
	return result; 
} 

private void printDetails(double amount) { 
	System.out.println("name: " + name); 
	System.out.println("amount: " + amount); 
}

Inline Method

메서드 기능이 단순하며 너무 뻔한 경우, 해당 메서드를 호출하는 곳에 메서드 내용을 직접 넣고 그 메서드는 삭제하는 메서드 내용 직접 삽입 리팩토링

수정 전

public int getRating() { 
	return (moreThanFiveLateDeliveries()) ? 2 : 1; 
} 

public boolean moreThanFiveLateDeliveries() { 
	return numberOfLateDeliveries > 5; 
}

수정 후

public int getRating() { 
	return (numberOfLateDeliveries > 5) ? 2 : 1; 
}

Inline Temp

간단한 수식을 대입받는 임시변수가 있어서 다른 리팩토링을 적용하기 힘들 경우, 임시변수를 참조하는 부분을 수식으로 치환하는 임시변수 내용 직접 삽입 리팩토링

수정 전

double basePrice = anOrder.basePrice(); 
return (basePrice > 1000);

수정 후

return (anOrder.basePrice() > 1000);

아래 블로그에서 더 많은 리팩토링이 기재되어 있으니 시간될 때 한번 읽어보자!!
(출처 : https://lelecoder.com/117)

Default Method

인터페이스 내 메소드 선언 시에 default를 명시하게 되면 인터페이스 내부에서도 로직이 포함된 메소드를 선언할 수 있다.

기존에 존재하던 인터페이스를 이용하여서 구현된 클래스를 만들고 사용하고 있는데 인터페이스를 보완하는 과정에서 추가적으로 구현해야 할 혹은 필수적으로 존재해야 할 메소드가 있다면, 이미 이 인터페이스를 구현한 클래스와의 호환성이 떨어 지게된다. 이러한 경우 default 메소드를 추가하게 된다면 하위 호환성은 유지되고 인터페이스의 보완을 진행 할 수 있다.
(출처 : https://siyoon210.tistory.com/95, https://boxfoxs.tistory.com/359)

접근제어자

접근 제어자는 private, default, protected, public이 있으며,
private → default → protected → public 순으로 보다 많은 접근을 허용한다.

접근 제어자접근 범위
private해당 클래스
default해당 패키지
protected동일 패키지내의 클래스 또는 해당 클래스를 상속받은 외부 패키지의 클래스
public모든 클래스

(출처 : https://wikidocs.net/232)

익명클래스

프로그램 내에서 한번만 객체로 만드는데 사용되는 클래스를 굳이 정의할 필요가 없다. 이럴 때 익명 클래스를 사용한다.

Find More

서블릿 개념

(참고 : https://hochoon-dev.tistory.com/entry/JAVA-Servlet%EC%84%9C%EB%B8%94%EB%A6%BF-%EC%9D%B4%EB%9E%80)

전략 패턴 및 템플릿 콜백 패턴

좋은 웹페이지 즐겨찾기