문제

예를 들어 오류를 기록하고 다음 요청으로 건너뛰고, 사용자에게 메시지를 표시하고 다음 이벤트를 처리하는 등 모든 오류를 동일한 방식으로 처리하려는 경우 확인되지 않은 예외는 괜찮습니다.이것이 나의 사용 사례라면 내가 해야 할 일은 시스템의 높은 수준에서 일반적인 예외 유형을 포착하고 모든 것을 동일한 방식으로 처리하는 것뿐입니다.

하지만 특정 문제에서 복구하고 싶은데 확인되지 않은 예외를 사용하여 이에 접근하는 가장 좋은 방법이 확실하지 않습니다.여기에 구체적인 예가 있습니다.

Struts2와 Hibernate를 사용하여 구축된 웹 애플리케이션이 있다고 가정해 보겠습니다.내 "작업"에 예외가 발생하면 이를 기록하고 사용자에게 예쁜 사과를 표시합니다.하지만 내 웹 애플리케이션의 기능 중 하나는 고유한 사용자 이름이 필요한 새 사용자 계정을 만드는 것입니다.사용자가 이미 존재하는 이름을 선택하면 Hibernate는 org.hibernate.exception.ConstraintViolationException (확인되지 ​​않은 예외) 내 시스템 내부에 있습니다.저는 "우리는 귀하의 문제를 기록했지만 지금은 귀하가 어려움을 겪고 있습니다"라는 동일한 메시지를 제공하는 대신 사용자에게 다른 사용자 이름을 선택하도록 요청하여 이 특정 문제를 복구하고 싶습니다.

고려해야 할 몇 가지 사항은 다음과 같습니다.

  1. 동시에 계정을 만드는 사람들이 많습니다.이름이 존재하는지 확인하기 위해 "SELECT"와 존재하지 않는 경우 "INSERT" 사이에 전체 사용자 테이블을 잠그고 싶지 않습니다.관계형 데이터베이스의 경우 이 문제를 해결하기 위한 몇 가지 트릭이 있을 수 있지만 제가 정말 관심을 갖는 것은 기본적인 경쟁 조건으로 인해 예외에 대한 사전 확인이 작동하지 않는 일반적인 경우입니다.파일 시스템에서 파일을 찾는 경우에도 동일한 작업이 적용될 수 있습니다.
  2. "Inc."의 기술 칼럼을 읽음으로써 유발된 드라이브 바이 관리에 대한 CTO의 성향을 고려할 때, 나는 Hibernate를 버리고 Kodo 등을 사용할 수 있도록 지속성 메커니즘에 대한 간접 계층이 필요합니다. 지속성 코드 계층.사실 내 시스템에는 이러한 추상화 계층이 여러 개 있습니다.확인되지 않은 예외에도 불구하고 누출을 방지하려면 어떻게 해야 합니까?
  3. 확인된 예외의 공개된 약점 중 하나는 스택의 모든 호출에서 이를 "처리"해야 한다는 것입니다. 호출 메서드가 해당 예외를 throw한다고 선언하거나 예외를 잡아서 처리해야 합니다.이를 처리한다는 것은 추상화 수준에 적합한 유형의 또 다른 확인된 예외로 래핑하는 것을 의미하는 경우가 많습니다.예를 들어, 검사 예외 영역에서 내 UserRegistry의 파일 시스템 기반 구현은 다음을 포착할 수 있습니다. IOException, 데이터베이스 구현에서는 SQLException, 그러나 둘 다 던질 것입니다 UserNotFoundException 이는 기본 구현을 숨깁니다.구현 세부 사항을 유출하지 않고 각 계층에서 래핑하는 부담을 덜고 확인되지 않은 예외를 어떻게 활용합니까?
도움이 되었습니까?

해결책

IMO, 래핑 예외(확인 또는 기타)에는 비용 대비 가치가 있는 여러 가지 이점이 있습니다.

1) 작성한 코드의 실패 모드에 대해 생각하도록 권장합니다.기본적으로 호출하는 코드에서 발생할 수 있는 예외를 고려해야 하며, 이어서 자신의 코드를 호출하는 코드에 대해 발생할 예외도 고려해야 합니다.

2) 예외 체인에 추가 디버깅 정보를 추가할 수 있는 기회를 제공합니다.예를 들어, 중복된 사용자 이름에 대해 예외를 발생시키는 메소드가 있는 경우 실패 상황에 대한 추가 정보(예: 중복된 사용자 이름을 제공한 요청의 IP)를 포함하는 메소드로 해당 예외를 래핑할 수 있습니다. 하위 수준 코드에서는 사용할 수 없습니다.예외에 대한 쿠키 추적은 복잡한 문제를 디버깅하는 데 도움이 될 수 있습니다(저에게는 확실히 그렇습니다).

3) 하위 레벨 코드로부터 구현 독립적이 될 수 있습니다.예외를 래핑하고 Hibernate를 다른 ORM으로 교체해야 하는 경우 Hibernate 처리 코드만 변경하면 됩니다.다른 모든 코드 계층은 래핑된 예외를 성공적으로 사용하고 기본 상황이 변경되더라도 이를 동일한 방식으로 해석합니다.이는 Hibernate가 어떤 방식으로 변경되더라도 적용된다는 점에 유의하십시오(예:새 버전에서는 예외를 전환합니다.이는 단지 도매 기술 교체만을 위한 것이 아닙니다.

4) 다양한 상황을 표현하기 위해 다양한 예외 클래스를 사용하도록 권장합니다.예를 들어 사용자가 사용자 이름을 재사용하려고 하면 DuplicateUsernameException이 발생할 수 있고, DB 연결이 끊어져 중복된 사용자 이름을 확인할 수 없으면 DatabaseFailureException이 발생할 수 있습니다.그러면 유연하고 강력한 방식으로 귀하의 질문("어떻게 회복합니까?")에 답할 수 있습니다.DuplicateUsernameException이 발생하는 경우 사용자에게 다른 사용자 이름을 제안하도록 결정할 수 있습니다.DatabaseFailureException이 발생하면 사용자에게 "유지 관리 중단" 페이지가 표시될 때까지 버블링을 허용하고 알림 이메일을 보낼 수 있습니다.사용자 정의 예외가 있으면 사용자 정의 가능한 응답이 제공됩니다. 이는 좋은 일입니다.

다른 팁

애플리케이션의 "계층"간에 예외를 다시 패키징하고 싶습니다. 예를 들어 DB 관련 예외는 내 애플리케이션의 맥락에서 의미있는 다른 예외 내부에 다시 패키징됩니다 (물론 원래 예외는스택 추적을 방해하지 않습니다.

즉, 고유하지 않은 사용자 이름은 던져야 할만큼 "예외적 인"상황이 아니라고 생각합니다.대신 부울 반환 인수를 사용합니다.귀하의 아키텍처에 대해 많이 알지 못하면 더 구체적이거나 적용 가능한 것을 말하기가 어렵습니다.

생성, 처리 및 오류 관리

분할 도메인 및 기술적 오류 패턴에서 <인용구>

기술적 오류로 인해 생성 될 도메인 오류 (절대 twain이 만나야합니다). 때 기술적 오류는 비즈니스를 유발해야합니다 처리가 실패하려면 SystemError로 래핑됩니다.

도메인 오류는 항상 도메인 문제 및 처리 도메인 코드.

도메인 오류는 기술을 통해 "원활하게"전달 경계. 그런 오류가 직렬화되고 재구성되어야합니다. 이것이 일어나기 위해. 프록시 및 파사드는 책임을 져야합니다 이렇게.

기술적 오류는 의 특정 지점에서 처리 경계와 같은 응용 프로그램 (참조 배포 경계에 로그인).

전달 된 컨텍스트 정보의 양 다시 오류가 발생하는 방법에 따라 유용 할 것입니다. 진단 및 처리 (구상 대체 전략). 당신은 스택 추적 여부에 대한 질문 원격 시스템은 전적으로 유용합니다. 도메인 오류 처리 (하지만 코드 위치는 당시의 오류 및 변수 값 유용 할 수 있음) 그래서, "UniqueUsernameException"과 같은 확인되지 않은 도메인 예외로 최대 절전 모드로 전환되도록 경계에서 최대 절전 모드 예외를 래핑하고 처리기까지 버블 링되도록합니다. 확인 된 예외가 아니더라도 throw 된 예외를 javadoc로 확인하십시오!

현재 최대 절전 모드를 사용하고 있으므로 가장 쉬운 방법은 해당 예외를 확인하고이를 사용자 정의 예외 또는 프레임 워크에서 설정 한 사용자 정의 결과 개체로 래핑하는 것입니다.나중에 최대 절전 모드를 버리고 싶다면이 예외를 한 곳에서만 래핑해야합니다. 우선 최대 절전 모드에서 예외를 포착하는 곳은 어쨌든 전환 할 때 변경해야 할 코드입니다.한곳에 있으면 추가 오버 헤드가 거의 지루해집니다.

도움?

닉에 동의합니다.설명한 예외는 실제로 "예기치 않은 예외"가 아니므로 가능한 예외를 고려하여 그에 따라 코드를 설계해야합니다.

또한 Microsoft Enterprise Library 예외 문서를 살펴 보는 것이 좋습니다.핸들링 블록 에는 오류 핸들링 패턴에 대한 멋진 개요가 있습니다.

확인되지 않은 예외를 래핑하지 않고도 포착 할 수 있습니다.예를 들어, 다음은 유효한 Java입니다. 라코 디스

따라서 액션 / 컨트롤러에서 Hibernate 호출이 이루어지는 로직 주위에 try-catch 블록을 가질 수 있습니다.예외에 따라 특정 오류 메시지를 렌더링 할 수 있습니다.

하지만 오늘은 Hibernate이고 내일은 SleepLongerDuringWinter 프레임 워크 일 수 있습니다.이 경우 타사 프레임 워크를 감싸는 자신 만의 작은 ORM 프레임 워크가있는 척해야합니다.이를 통해 프레임 워크 별 예외를 더 의미있는 방법을 알고있는보다 의미 있고 / 또는 확인 된 예외로 래핑 할 수 있습니다.

  1. 이 질문은 확인 된 토론과 확인되지 않은 토론과는 관련이 없으며 두 예외 유형 모두에 동일하게 적용됩니다.

  2. ConstraintViolationException이 발생하는 지점과 멋진 오류 메시지를 표시하여 위반을 처리하려는 지점 사이에는 즉시 중단되어야하고 신경 쓰지 않아야하는 스택의 많은 메서드 호출이 있습니다. 문제에 대해. 따라서 예외에서 값을 반환하도록 코드를 재 설계하는 것과는 반대로 예외 메커니즘이 올바른 선택이됩니다.

  3. 사실, 확인 된 예외 대신 확인되지 않은 예외를 사용하는 것은 자연스럽게 적합합니다. 호출 스택의 모든 중간 메서드가 예외를 무시 하고 처리 .

  4. 사용자에게 멋진 오류 메시지 (오류 페이지)를 표시하는 것만으로 "고유 이름 위반"을 처리하려면 특정 DuplicateUsernameException이 실제로 필요하지 않습니다. 이것은 예외 클래스의 수를 낮게 유지합니다. 대신 많은 유사한 시나리오에서 재사용 할 수있는 MessageException을 생성 할 수 있습니다.

    가능한 한 빨리 ConstraintViolationException을 포착하고이를 멋진 메시지와 함께 MessageException으로 변환합니다. 조만간 변환하는 것이 중요합니다. 확실히 위반 된 것은 "고유 한 사용자 이름 제약"이며 다른 제약 조건이 아닙니다.

    최상위 핸들러와 가까운 곳에서 MessageException을 다른 방식으로 처리하십시오. "문제를 기록했지만 지금은 문제가 없습니다"대신 단순히 MessageException에 포함 된 메시지를 표시하고 스택 추적은하지 않습니다.

    MessageException은 문제에 대한 자세한 설명, 사용 가능한 다음 작업 (취소, 다른 페이지로 이동), 아이콘 (오류, 경고) 등의 추가 생성자 매개 변수를 취할 수 있습니다 ...

    코드는 다음과 같습니다. 라코 디스

    완전히 다른 곳에 예외 처리기가 있습니다. 라코 디스

@Jan 선택 또는 선택 취소는여기에 핵심적인 문제.나는 중간 프레임에서 예외가 무시되어야한다는 당신의 가정 (# 3)에 의문을 제기합니다.이렇게하면 상위 수준 코드에서 구현 별 종속성이 발생합니다.Hibernate를 대체하면 애플리케이션 전체에서 catch 블록을 수정해야합니다.그러나 동시에 하위 수준에서 예외를 포착하면 확인되지 않은 예외를 사용하여 많은 이점을 얻지 못합니다.

또한 여기서 시나리오는 특정 논리적 오류를 포착하고 사용자에게 다른 ID를 다시 프롬프트하여 애플리케이션의 흐름을 변경하려는 것입니다.표시된 메시지를 변경하는 것만으로는 충분하지 않으며, 예외 유형에 따라 다른 메시지에 매핑하는 기능은 이미 서블릿에 내장되어 있습니다.

@erikson

생각에 음식을 추가하기 만하면됩니다.

선택 및 선택 안 함은 여기에서 논의

확인되지 않은 예외의 사용은 함수 호출자에 의해 발생하는 예외에 대해 IMO가 사용된다는 사실을 준수합니다 (호출자는 해당 함수 위에 여러 계층이있을 수 있으므로 다른예외를 무시할 프레임)

특정 문제와 관련하여 높은 수준에서 확인되지 않은 예외를 포착하고 @Kanook이 말한대로 호출 스택을 표시하지 않고 자체 예외에서 캡슐화해야합니다 (@Jan Soltis에서 언급 함)

즉, 기본 기술이 변경되면 실제로 코드에 이미있는 catch ()에 영향을 미치며 최신 시나리오에 대한 답변이 아닙니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top