본문 바로가기
Spring-Boot

토비의 스프링 3.1 Vol.1 250p ~ 350p 정리

by 준형코딩 2023. 12. 30.

3.5.3 템플릿/콜백의 응용

- 템플릿 / 콜백의 재설계

- 제네릭스를 이용한 콜백 인터페이스

제네릭스를 적용하여 다양한 오브젝트 타입을 지원하는 인터페이스나 메소드를 정의해 보자.

//타입 파라미터를 적용한 LineCallback
public inteface LineCallback<T> {
	T doSomethingWithLine(String line, T value);
}
//타입 파라미터를 추가해서 제네릭 메소드로 만든 lineReadTemplate()
public <T> T lineReadTemplate(String filepath, LineCallback<T> callback, T initVal)
	throws IOException {
		...    
}

 

3.7 정리

- JDBC와 같은 예외가 발생할 가능성이 있으며 공유 리소스의 반환이 필요한 코드는 반드시 try/catch/finally 블록으로 관리해야 ㅇ한다.

- 일정한 작업 흐름이 반복되면서 그중 일부 기능만 바뀌는 코드가 존재한다면 전략 패턴을 적용한다. 바뀌지 않는 부분은 컨텍스트로, 바뀌는 부분은 전략으로 만들고 인터페이스를 통해 유연하게 전략을 변경할 수 있도록 구성한다.

- 같은 애플리케이션 안에서 여러 가지 종류의 전략을 다이내믹하게 구성하고 사용해야 한다면 컨텍스트를 이용하는 클라이언트 메소드에서 직접 전략을 정의하고 제공하게 만든다.

- 클라이언트 메소드 안에 익명 내부 클래스를 사용해서 전략 오브젝트를 구현하면 코드도 간결해지고 메소드의 정보를 직접 사용할 수 있어서 편리하다.

- 컨텍스트가 하나 이상의 클라이언트 오브젝트에서 사용된다면 클래스를 분리해서 공유하도록 만든다.

- 컨텍스트는 별도의 빈으로 등록해서 DI 받거나 클라이언트 클래스에서 직접 생성해서 사용한다. 클래스 내부에서 컨텍스트를 사용할 때 컨텍스트가 의존하는 외부의 오브젝트가 잇다면 직접 DI 해줄 수 있다.

- 단일 전략 메소드를 갖는 전략 패턴이면서 익명 내부 클래스를 사용해서 매번 전략을 새로 만들어 사용하고, 컨텍스트 호출과 동시에 전략 DI를 수행하는 방식을 템플릿/콜백 패턴이라고 한다.

- 콜백의 코드에도 일정한 패턴이 반복된다면 콜백을 템플릿에 넣고 재활용하는 것이 편리하다.

- 템플릿과 콜백의 타입이 다양하게 바뀔 수 잇다면 제네릭스를 이용한다.

- 스프링은 JDBC 코드 작성을 위해 JdbcTemplate을 기반으로 하는 다양한 템플릿과 콜백을 제공한다.

- 템플릿은 한 번에 하나 이상의 콜백을 사용할 수도 있고, 하나의 콜백을 여러 번 호출할 수도 있다.

- 템플릿/콜백을 설계할 때는 템플릿과 콜백 사이에 주고받는 정보에 관심을 둬야 한다.

4장. 예외

4.1 사라진 SQLException

JdbcContext -> JdbcTemplate SQLException이 사라진 것을 볼 수 있다. 어디로 간 것 일까?

4.1.1 초난감 예외처리

- 예외 블랙홀

모든 예외는 적절하게 복구되든지 아니면 작업을 중단시키고 운영자 또는 개발자에게 분명하게 통보돼야 한다.

 

- 무의미하고 무책임한 throws

//매우 안 좋은 예외처리 방법의 예, 의미없는 예외 호출
public void method1() throws Exception {
	method2();
}

public void method2() throws Exception {
	method3();
}

public void method3() throws Exception {
	...
}

4.1.2 예외의 종류와 특징

- Error

java.lang.Error 클래스의 서브클래스들이다. 에러는 시스템에 뭔가 비정상적인 상황이 발생했을 경우에 사용된다.

 

- Exception과 체크 예외

개발자들이 만든 애플리케이션 코드의 작업 중에 예외상황이 발생했을 경우에 사용

체크 예외 - Exception 클래스의 서브클래스이면서 RuntimeException 클래스를 상속하지 않을 것들

언체크 예외 - RuntimeException 클래스를 상송한 것들

일반적인 예외라고 보면 된다.

 

- RuntimeException과 언체크/런타임 예외

java.lang.RuntimeException 클래스를 상속한 예외들은 명시적인 예외처리를 강제하지 않기 때문에 언체크 예외라고 불린다.

4.1.3 예외처리 방법

- 예외 복구

예외상황을 파악하고 문제를 해결해서 정상 상태로 돌려놓는 것

 

- 예외처리 회피

예외처리를 자신이 담당하지 않고 자신을 호출한 쪽으로 던져버리는 것

 

- 예외 전환

예외를 메소드 밖으로 던지는 것, 예외 회피와 달리 발생한 예외를 그대로 넘기는 게 아니라 적절한 예외로 전환해서 던진다는 특징이 있다.

4.1.4 예외처리 전략

- 런타임 예외의 보편화

대응 불가능한 체크 예외라면 빨리 런타임 예외러 전환해서 던지는 게 낫다.

 

- add() 메소드의 예외처리

- 애플리케이션 예외

4.1.5 SQLException은 어떻게 됐나?

필요도 없는 기계적인 throws 선언이 등장하도록 방치하지 말고 가능한 한 빨리 언체크/런타임 예외로 전환해줘야 한다.

스프링의 JdbcTemplate은 바로 이 예외처리 전략을 따르고있다. JdbcTemplate 템플릿과 콜백 안에서 발생하는 모든 SQLException을 런타임 예외인 DataAccessException으로 포장해서 던져준다.

4.2 예외 전환

4.2.1 JDBC의 한계

- 비표준 SQL

- 호환성 없는 SQLException의 DB 에러 정보

4.3 정리

- 예외를 잡아서 아무런 조치를 취핮 ㅣ않거나 의미 없는 throws 선언을 남발하는 것은 위험하다.

- 예외는 복구하거나 예외처리 오브젝트로 의도적으로 전달하거나 적절한 예외로 전환해야한다.

- 좀 더 의미 있는 예외로 변경하거나, 불필요한 catch/throws를 피하기 위해 런타임 예외로 포장하는 두 가지 방법의 예외 전환이 있다.

- 복구할 수 없는 예외는 가능한 한 빨리 런타임 예외로 전환하는 것이 바람직하다.

- 애플리케이션의 로직을 담기 위한 예외는 체크 예외로 만든다.

- JDBC의 SQLException의 에러 코드는 DB에 종속되기 때문에 DB에 독립적인 예외로 전환될 필요가 있다.

- 스프링은 DataAccessException을 통해 DB에 독립적으로 적용 가능한 추상화된 런타임 예외 계층을 제공한다.

- DAO를 데이터 액세스 기술에서 독립시키려면 인터페이스 도입과 런타임 예외 전환, 기술에 독립적인 추상화된 예외로 전환이 필요하다.

5장. 서비스 추상화

5.1 사용자 레벨 관리 기능 추가

5.1.1 필드 추가

- Level enum

int 상수로 level을 정의해 줄 수는 있지만 다른 종류의 정보를 넣는 실수를 해도 컴파일러가 체크해주지 못하기 때문에 심각한 오류가 발생할 수 있다. enum을 사용해서 안전하고 편리하게 기능을 만들자.

 

- User 필드 추가

public class User {
	...
	Level level;
    int login;
    int recommend;
    
    public Level getLevel() {
    	return level;
    }
    ... 
}

 

- UserDaoTest 테스트 수정

- UserDaoJdbc 수정

5.1.2 사용자 수정 기능 추가

- 수정 기능 테스트 추가

- UserDao와 UserDaoJdbc 수정

- 수정 테스트 보완

5.1.3 UserService.upgradeLevels()

- UserService 클래스와 빈 등록

- UserServiceTest 테스트 클래스

- UpgradeLevels() 메소드

- UpgradeLevels() 테스트

5.1.4 UserService.add()

사용자 관리에 대한 비즈니스 로직을 담고 있는 UserService에 사용자의 level을 basic으로 세팅해 주는 메소드를 만들자.

5.1.5 코드 개선

- upgradeLevels() 메소드 코드의 문제점

if else를 많이 사용하여 코드가 깔금하지 않음

 

- upgradeLevels() 리팩토링

1. swith를 사용하여 깔금하게 리팩토링하자.

2. 예외처리 기능을 만들어주자.

 

- User 테스트

- UserServiceTest 개선

5.2 트랜잭션 서비스 추상화

5.2.1 모 아니면 도

- 테스트용 UserService 대역

UserService를 상속해서 일부 메소드를 오버라이딩

대부분 private으로 되어 있기에 protected로 변경 <- 권장되는 방법은 아님, 이번만큼은 예외