Download presentation
Presentation is loading. Please wait.
Published byEmma Mattila Modified 5년 전
1
Sep. 2014 Youn-Hee Han http://link.koreatech.ac.kr
Chapter 04. 예외 Sep. 2014 Youn-Hee Han
2
4.1 사라진 SQLException
3
4.1.0 SQLException 예외 처리 삭제 3장에서 구성한 JdbcContext와 스프링의 JdbcTemplate의 예외처리 부분 비교 JdbcTemplate을 사용하는 경우 SQLException 예외를 던지는 코드가 생략됨
4
4.1.1 초난감 예외처리 개발자들의 코드에 발견되는 초난감 예외처리 종류 예외 블랙홀 가장 최악의 예외 처리 방법
결국 어떤 기능이 비정상적으로 동작하거나, 메모리나 리소스가 소진되거나, 예상치 못한 문제를 일으킬 것
5
4.1.1 초난감 예외처리 개발자들의 코드에 발견되는 초난감 예외처리 종류 단순 콘솔 출력
화면에 출력된 메시지를 보고 바로바로 조취를 취하면 그나마 괜찮음 운영서버에 올라가면 콘솔을 모니터링하기 힘듦 단순 콘솔 출력은 예외가 적절하게 처리된 것이 아니다.
6
4.1.1 초난감 예외처리 예외 처리에 대한 기본 원칙 앞의 코드 보다는 차라리 다음 코드가 좋다
예외는 처리되거나 아니면 작업을 중단하고 운영자 또는 개발자에게 분명하게 통보되어야 한다. 앞의 코드 보다는 차라리 다음 코드가 좋다 실전에서 이렇게 만들면 안되다. 단지 예외를 무시하거나 잡아먹어 버리는 코드를 만들지 말라는 차원에서 그나마 나은 코드 굳이 예외를 잡아서 뭔가 조치를 취할 방법이 없다면 잡지 말고 차라리 자신을 호출한 코드에 예외처리 책임을 전가하라.
7
4.1.1 초난감 예외처리 무의미하고 무책임한 throws 기계적으로 throws Exception을 붙인 코드
중요한 예외 상황에 대한 파악을 제대로 할 수 없고, 그러한 예외 상황 발생에 대해 무조건 던져버린다. 적절한 처리를 통해 복구가 어렵지 않게 가능한 예외상황도 제대로 처리할 수 있는 기회를 박탈당한다.
8
4.1.2 예외의 종류와 특징 java.lang.Error java.lang.Error 클래스의 서브클래스에 해당하는 에러들
java.lang.OutOfMemoryError ThreadDeath 시스템에 뭔가 비정상적인 상황이 발생한 경우에 발생 주로 자바 virtual machine에서 발생시키는 것 개발자 코드에서 잡을 필요도 없고 신경 쓰지 않아도 된다. 잡아도 대처할 수 있는 바가 전혀 없음
9
4.1.2 예외의 종류와 특징 java.lang.Exception 개발자들이 만든 애플리케이션 코드의 작업 중에 발생한 예외
두가지 종류 언체크 예외 (Unchecked Exception)/런타임 예외 체크 예외 (Checked Exception)
10
4.1.2 예외의 종류와 특징 언체크 예외 (Unchecked Exception)
java.lang.RuntimeException 클래스를 상속한 예외들 런타임 예외라고도 불림 대표적인 언체크 예외 NullPointerException IllegalArgumentException ArrayIndexOutOfBoundException 언체크/런타임 예외가 발생할 수 있는 메소드 호출시에는 catch 문으로 잡거나 throws로 선언하거나 또는 하지 않아도 된다. 미리 주의 깊게 코딩을 한다면 모두 피할 수 있는 예외
11
4.1.2 예외의 종류와 특징 체크 예외 (Checked Exception) 최근의 자바 개발자 커뮤니티 상황
일반적으로 말하는 예외 체크 예외가 발생함이 선언된 메소드를 사용할 경우 반드시 예외를 처리하는 코드가 있어야 함 자신의 메소드 안에서 해당 메소드 호출에 try/catch 블록 적용, 또는 throws 를 통해 자신의 메소드 밖으로 던짐 최근의 자바 개발자 커뮤니티 상황 체크 예외의 강제성 때문에 난잡한 코드가 남발됨을 근거로 체크 예외의 불필요성을 주장하는 사람들이 늘어남
12
4.1.3 예외처리 방법 예외 복구 예외상황을 파악하고 문제를 해결하여 정상 상태로 돌리는 방법
1) 기본 작업 흐름이 불가능하면 다른 작업 흐름으로 유도해줌 예. 파일을 읽으려고 하는데 해당 파일이 없을 때 IOException 발생 (체크 예외) 복구 방법 사용자에게 이를 알리고 다른 파일을 읽도록 유도 2) 재시도를 통한 예외 복구 예. 원격 DB 서버 접속시 연결 설정이 잘 안되면 재시도를 정해진 횟수만큼 재시도
13
4.1.3 예외처리 방법 예외 처리 회피 예외 처리를 자신이 담당하지 않고 자신을 호출한 쪽으로 던짐 무책임한 회피는 곤란
자신을 호출한쪽에서 예외를 처리하는 것이 좋다는 판단이 있을 때에만 회피하고 throw 함 예. JdbcTemplate에서 정의하는 콜백 메소드는 모두 throws SQLException이 붙어 있음. 즉, 콜백 자체에서 처리하는 것이 아니라 이를 호출하는 JdbcTemplate에서 처리하도록 유도하고 있음 즉, 자신과 긴밀한 연관관계가 있는 객체일 때에만 예외 처리를 넘김
14
4.1.3 예외처리 방법 예외 전환(Exception Translation)후 회피
발생한 예외를 그대로 넘기는 게 아니라, 일단 잡아서 적절한 다른 예외로 전환하여 던짐 예외 전환 목적 1 - 그대로 던지는 것 보다 보다 그 의미를 분명하게 해줄 수 있는 예외로 변환하기 위해 좀 더 의미가 분명한 구체적 명칭의 예외 클래스를 작성하여 활용
15
4.1.3 예외처리 방법 예외 전환(Exception Translation)후 던짐(회피)
예외 전환 목적 1 - 그대로 던지는 것 보다 보다 그 의미를 분명하게 해줄 수 있는 예외로 변환하기 위해 중첩 예외 (Nested exception) 그 의미를 분명하기 하기 위하여 새로운 예외를 만들 때 원래 발생했던 예외를 새로운 예외 안에 넣어주는 방법
16
4.1.3 예외처리 방법 예외 전환(Exception Translation)후 던짐(회피)
예외 전환 목적 2 - 예외 처리를 쉽고 단순하게 만들기 위해 포장(Wrap)하는 것 주로 예외처리를 강제하는 체크 예외를 언체크 예외인 런타임 예외로 포장하는 방법 예. EJB 컴포넌트에서 발생하는 대부분의 체크 예외는 비즈니스 로직상 복구 가능한 예외가 아닌 경우가 많음 이런 경우 런타임 예외인 EJBException으로 포장하여 던지는 것이 낫다.
17
4.1.3 예외처리 방법 예외 전환(Exception Translation)후 던짐(회피) 요즘의 경향
예외 전환 목적 2 - 예외 처리를 쉽고 단순하게 만들기 위해 포장(Wrap)하는 것 몇가지 런타임 예외는 코딩상에서 특별하게 잡아 처리하지 않아도 스프링 자체 라이브러리 상에서 직접 잡아서 처리를 해줌 예. 트랜잭션 롤백 요즘의 경향 어차피 복구가 불가능한 예외라면 애플리케이션 코드에서는… 1) 자세한 로그를 남김 2) 관리자에게 이메일 통보 3) 사용자에게는 친절한 안내 메시지 4) 마지막으로, 런타임 예외로 포장해서 던짐
18
4.1.4 예외처리 전략 런타임 예외의 보편화 여러 체크 예외에 대한 try/catch 블록의 강제적 사용
자바 초기때 만들어진 정책 하지만 최근에는 많은 개발자들로 부터 비판을 받음 특히 자바가 서버 환경에서 사용될 때… 외부 환경에 인한 여러 예외 발생에 대해 프로그램 코드상으로 처리할 수 없는 상황이 많음 이런 경우 예외 전환을 사용하여 런타임 예외로 전환하여 던지는 것 추천 즉, 최근에는 새로운 예외 클래스를 정의할 때 항상 복구가 가능한 예외만 체크 예외로 만든다. 항상 복구 할 수 없다면 런타임 예외로 만든다. 런타임 예외를 사용한 예외 처리 낙관적 접근법
19
4.1.4 예외처리 전략 add() 메소드(리스트 4-9)의 예외처리 분석 및 변경
DuplicatedUserIdException 자신 또는 호출한 쪽에서 충분히 복구 가능한 예외 자신이 처리해도 되지만 여기서는 런타임 예외로 전환 및 던짐 만약 아이디를 호출한 쪽에서 정하여 넣었다면 호출한 쪽으로 던져서 아이디가 중복되었음을 알리는 것이 좋음 호출한 쪽에서 신경을 쓰지 않아도 되는 상황일 수도 있으니 런타임 예외 전환이 좋음 add() 메소드 자체에서 본 예외 던짐을 선언하여 이용하는 쪽에서 예외 발생 상황을 정확하게 파악하게 함 SQLException 잡아보았자 복구 불가능한 예외 런타임 예외로 포장하여 그냥 던짐 (어느 정도 회피의 측면) add() 메소드 자체에 본 예외 던짐 선언 생략해도 됨 필요하면 호출한 쪽에서 try/catch 블록을 넣어 잡아서 적절한 처리 가능
20
4.1.4 예외처리 전략 add() 메소드(리스트 4-9)의 예외처리 분석 및 변경
DuplicatedUserIdException을 Runtime 예외로 선언 적절한 예외 처리 전략이 적용된 add()
21
4.1.4 예외처리 전략 add() 메소드(리스트 4-9)의 예외처리 분석 및 변경
SQLException에 대해서는 전혀 신경쓰지 않아도 됨 필요한 경우에는 DuplicatedUserIdException을 잡아서 적절한 처리 가능. 필요없으면 역시 신경쓰지 않아도 됨 런타임 예외 전환에 대한 주의점 컴파일러가 예외처리를 강제하지 않으므로 예외상황에 너무 둔감해질 수 있음 주의 API 문서 등을 잘 작성하여 본 메소드에서 발생할 수 있는 예외의 종류, 원인, 활용 방법 등을 설명해 둘 필요가 있음 라이브러리로 제공되는 객체의 메소드를 활용할 때 이 때에도, API 문서를 활용하여 해당 메소드를 사용할 때 발생할 수 있는 여러 예외에 대해 검토 필요
22
4.1.4 예외처리 전략 애플리케이션 예외 외부 환경이 아니라 애플리케이션 자체의 로직에 의해 의도적으로 발생시키고, 반드시 catch하여 무엇인가 조치를 취하도록 강제적으로 요구하는 예외 예: 예금 인출 (withdraw)시 잔고 부족 예외 반드시 체크 예외로 InsufficientBalanceException을 발생 시킴
23
4.1.5 SQLException은 어떻게 되었나? SQLException 99% 런타임시에 코드 레벨에서 복구 방법이 없다.
프로그램의 오류 또는 개발자의 부주의 때문에 발생된 에러 SQL 문법 오류 DB 제약조건 위반 (foreign key, unique key등…) DB 서버 다운 네트워크 불안정 DB 커넥션 풀에서 커넥션을 가져올 수 없음 DAO를 호출한 밖에서 이를 복구할 방법은 더욱 없다. 필요도 없는 기계적인 try/catch 블록이나 throws 선언이 등장하지 않도록 방치하지 말고 런타임 예외로 전환 필요
24
4.1.5 SQLException은 어떻게 되었나? 스프링의 JdbcTemplate 의 예외 처리 전략
템플릿과 콜백에서 발생하는 모든 SQLException을 런타임 예외인 DataAccessException으로 전환하여 던짐 템플릿과 콜백을 사용하는 측에서는 필요한 경우 DataAccessException을 잡아서 적절한 처리 그 외의 경우 무시해도 됨
25
4.2 예외 전환
26
4.2.0 스프링의 예외 전환 JdbcTemplate의 DataAccessException 예외 런타임 예외
SQLException을 포장함 또한, 상세한 예외정보를 의미 있고 일관성 있는 예외로 전환하여 추상화 하려는 의도
27
4.2.1 JDBC의 한계 표준화된 JDBC API의 한계 첫번째 문제점 – 비표준 SQL
비표준 SQL이 DAO 코드에 들어가면 해당 DAO는 그 DB에 종속됨 해결책 DAO를 DB별로 각각 구현함 SQL을 DAO 외부로 독립 (xml 등…)시켜서 쉽게 변경하여 사용할 수 있게 해줌 7장 참고
28
4.2.1 JDBC의 한계 두번째 문제점 – 호환성 없는 SQLException의 에러 정보
대신 getErrorCode()로 발생한 에러 코드를 넘겨줌 예. 중복 키 에러 처리 (MySQL 전용 코드) 하지만, DB별로 이 에러 코드가 서로 다름 위 코드는 오라클이나 SQLServer에서 사용할 수 없음 추가로 getSQLState() 메소드로 상태 코드를 던져주긴 하지만 이 마저도 DB 마다 제각각임 결국 호환성 없는 에러 코드와 상태코드를 지닌 SQLException만으로 DB에 독립적인 유연한 코드 작성은 불가능
29
4.2.2 DB 에러 코드 매핑을 통한 전환 스프링에서 제공하는 DataAccessException의 서브 클래스
BadSqlGrammarException SQL 문법 오류 DataAccessResourceFailureException DB 커넥션을 가져오지 못했을 때 DataIntegrityViolationException 데이터의 제약조건을 위배했거나 일관성을 지키지 않는 작업 수행 DuplicateKeyException 중복 키 문제 이 외에도 수십가지가 있음 참고
30
4.2.2 DB 에러 코드 매핑을 통한 전환 스프링에서 DB 마다 에러 코드가 다른 점에 대한 대처
DB별로 에러 코드를 분류하여 스프링이 정의한 예외 클래스와 매핑해 놓은 테이블 (XML 설정)을 만들어 두고 활용 예. 오라클용 에러 코드 및 매핑 정보
31
4.2.2 DB 에러 코드 매핑을 통한 전환 스프링에서 DB 마다 에러 코드가 다른 점에 대한 대처
기존 add() 메소드 변경 예외가 발생하면 JdbcTemplate에서 DuplicateKeyException안에 기존 SQLException을 넣어줌 add()을 호출하는 쪽에서 중복 키 상황에 대한 대응이 필요하면 조치를 취할 수 있도록 메소드 선언에 DuplicateKeyException 기입 추천 DB가 변경되어도 동일 조건하에 발생되는 에러는 동일한 예외를 받을 수 있음
32
4.2.2 DB 에러 코드 매핑을 통한 전환 런타임 예외를 체크 예외로 전환
DuplicateKeyException과 같은 중요한 예외는 반드시 add()를 호출한 측에서 처리하도록 강제하고 싶을 때 체크 예외인 DuplicateUserIdException 클래스 등을 만들어 다음과 같이 예외 전환할 수도 있음
33
4.2.3 DAO 인터페이스와 DataAccessException 계층구조
데이터 엑세스 로직을 담은 코드를 성격이 다른 코드에서 분리 전략 패턴을 적용하여 구현 방법을 변경해서 사용하기 위해 DAO를 사용하는 클라이언트에서는 DAO가 내부에서 어떤 데이터 엑세스 기술을 사용하는지 신경쓰지 않아도 된다. DataAccessException의 중요 특징 데이터 엑세스 기술의 종류와 상관없이 일관된 예외가 발생하도록 만들어줌 JDBC, JDO/JPA, iBatis 즉, 데이터 엑세스 기술에 독립적인 추상화된 예외 제공
34
4.2.3 DAO 인터페이스와 DataAccessException 계층구조
DAO에서 사용하는 데이터 엑세스 기술의 API가 예외를 던지는 것을 고려하여 DAO 인터페이스 선언 필요 만약 데이터 엑세스에 종속적으로 예외 선언을 하게 되면… JDBC보다 늦게 등장한 JPA, Hibernate, JDO는 위 예외들을 모두 런타임예외로 선언함 위와 같은 선언 필요 없음 아래와 같은 선언은 매우 무책임한 선언 JDBC를 위한 SQLException을 런타임 예외로 전환한다면 다음 처럼 선언해도 됨 하지만, 중복 키 예외와 같이 호출한 쪽으로 예외 상황을 알려주어야 할 필요도 있음. //JDBC
35
4.2.3 DAO 인터페이스와 DataAccessException 계층구조
중복 키 에러가 발생했을 때의 예외 종류 JDBC: SQLException JPA: PersistenceException Hibernate: HivernateException 따라서, DAO를 사용하는 클라리언트 측에서는 DAO의 사용 기술에 따라 예외 처리 방법이 달라져야 한다. 문제 심각 스프링의 해결책 다양한 엑세스 기술을 사용할 때 발생하는 예외들을 추상화하여 DataAccessException 계층구조 안에 정리하여 새롭게 예외들을 정의하였음
36
4.2.3 DAO 인터페이스와 DataAccessException 계층구조
o.s.dao.InvalidDataAccessResourceUsageException 데이터 엑세스 기술을 부정확하게 사용하였을 때, SQL 문이 잘못되었을 때, 타입을 잘 못 사용하면서 데이터를 입력하려고 할 때… o.s.dao.OptimisticLockingFailureException 낙관적 락킹과 관련된 예외
37
4.2.3 DAO 인터페이스와 DataAccessException 계층구조
o.s.dao.IncorrectResultSizeDataAccessException queryForObject()에서 하나 이상의 로우가 리턴될 때 o.s.dao.EmptyResultDataAccessException 기대한 결과가 하나도 리턴이 안될 때
38
4.2.4 기술에 독립적인 UserDao 만들기 인터페이스 적용 인터페이스: UserDao
인터페이스에 setDataSource() 메소드 추가 금지 UserDao를 사용하는 클라이언트에서 사용할 필요가 없는 메소드 클래스: UserDaoJdbc, UserDaoJpa, UserDaoHibernate 클래스 선언 XML 설정 일반적으로 빈의 이름 (id)은 인터페이스 이름을 따라 구성한다.
39
4.2.4 기술에 독립적인 UserDao 만들기 테스트 보완 테스트 코드 내의 UserDao는 그대로 사용
@Autowired는 스프링의 컨텍스트 내에 정의된 빈중에서 인스턴스 변수에 주입이 가능한 타입의 빈을 찾아 넣어준다. UserDao 동작에 관심이 있으면서 일종의 UserDao의 클라이언트로 테스트가 동작하기 때문에 구체적인 구현 클래스인 UserDaoJdbc로 변경할 필요 없음
40
4.2.4 기술에 독립적인 UserDao 만들기 테스트 보완 중복된 키를 가진 정보 등록 테스트
테스트 수행 성공 확인 (expected=DataAccessException.class)를 제외하고 실행하였을 경우에 콘솔 창에서 확인 가능한 메시지
Similar presentations