====== Exception Handling 서비스 ======
===== 개요 ======
전자정부 표준프레임워크 기반의 시스템 개발시 Exception 처리, 정확히는 Exception 별 특정 로직(후처리 로직이라고 부르기도 함)을 흐를 수 있도록 하여
Exception 에 따른 적절한 대응이 가능도록 하고자 하는데 목적이 있다.\\
AOP 의 도움을 받아 비즈니스 POJO와 분리되어 After throwing advice 로 정의하였다.\\
AOP 관련한 내용은 [[egovframework:rte:fdl:aop|AOP 모듈]]을 참조하길 바란다.\\
Exception 에 대해 이야기 하겠다.\\
Exception 이 발생시 Exception 발생 클래스 정보와 Exception 종류가 중요하다. \\
Exception 발생 클래스 정보와 Exception 종류는 모두 후처리 로직의 대상일지 아닐지를 결정하는데 사용된다.\\
전자정부 표준프레임워크 기반의 처리되는 Exception 은 현재 EgovBizException , DataAccessException , FdlException , 그외 나머지 로 구분되어 나누었다.\\
**EgovBizException** 은 Biz flow 상에 Biz Exception 으로 processException 메소드를 이용하여 아래와 같이 쓰인다. \\
public CategoryVO selectCategory(CategoryVO vo) throws Exception {
CategoryVO resultVO = categoryDAO.selectCategory(vo);
try {
....
// 넘어온 resultVO 가 null 인경우 EgovBizException 발생 (result.nodata.msg 는 메세지 키에 해당됨)
if (resultVO == null)
throw processException("result.nodata.msg");
// 또는 throw processException("result.nodata.msg", 발생한 Excpetion );
return resultVO;
}
**DataAccessException** 의 경우는 Spring 에서 persistence layer 에서 발생하는 Exception 에 대한 후처리를 위해 구분하였다. \\
FdlException 는 egovframe 내부에서 발생하는 Exception 을 위해 구분 해두었다. \\
**FdlException** 은 전자정부 표준프레임워크 에서 확장/추가된 영역에서 던져주는 Exception 이다. \\
**그외 나머지** 는 앞에서 나열한 Exception 을 제외한 Exception 이다.
Exception 을 발생한다는 것은 presentation layer 까지 Exception 을 던지겠다는 의도이다.
하지만 Exception 을 던지지 않고 Exception 후처리 로직처럼 수행후 계속 비즈니스로 돌아오는 방법도 필요할 것이다.
이것을 위해 **leaveaTrace 메소드** 가 존재한다. 파라미터로 존재하는 것은 메세지 키이다.
public CategoryVO selectCategory(CategoryVO vo) throws Exception {
CategoryVO resultVO = categoryDAO.selectCategory(vo);
try {
//강제로 발생한 ArithmeticException
int i = 1 / 0;
} catch (ArithmeticException athex) {
//Exception 을 발생하지 않고 후처리 로직 실행.
leaveaTrace("message.trace.msg");
}
return resultVO;
}
===== 설명 =====
우리는 앞에서 언급했던 Exception 후처리 방식과 Exception 이 아니지만 후처리 로직(leavaTrace)을 실행할 하는 방식에 대해 설명하도록 하겠다. \\
간략하게 보면 \\
Exception 후처리 방식은 ** AOP(pointCut => after-throw) => ExceptionTransfer.transfer() => ExceptionHandlerService => Handler ** 순으로 실행된다. \\
LeavaTrace 는 AOP를 이용하는 구조는 아니고 Exception 을 발생하지도 않는다. 단지 후처리 로직을 실행하도록 하고자 함에 목적이 있다.\\
실행 순서는 ** LeavaTrace => TraceHandlerService => Handler ** 순으로 실행한다. \\
먼저 Exception Handling 에 대해 알아보도록 하자.
==== Aop Config, ExceptionTransfer 설정 및 설명 ====
----
=== Bean 설정 ===
Exception 후처리와 leaveaTrace 설정을 위해서 샘플에서는 두개의 xml 파일을 이용한다. (context-aspect.xml, context-common.xml)
먼저 Exception 후처리를 위한 부분을 보겠다.\\
Exception Handling 을 위한 AOP 설정은 아래와 같다. \\
비즈니스 개발시 패키지 구조는 바뀌기 때문에 Pointcut은 egov.sample.service.*Impl.*(..)) 을 수정하여 적용할 수 있다.\\
ExceptionTransfer 의 property 로 존재하는 exceptionHandlerService 는 다수의 HandleManager 를 등록 가능하도록 되어 있다.\\
여기서는 defaultExceptionHandleManager을 등록한 것을 볼 수 있다. \\
**context-aspect.xml**
...
**service.*Impl
...
defaultExceptionHandleManager는 setPatters() , setHandlers() 메소드를 가지고 있어 상단과 같이 \\
등록된 pattern 정보를 이용하여 Exception 발생 클래스와의 비교하여 ture 인 경우 handlers 에 등록된 handler를 실행한다.\\
패턴 검사시 사용되는 pathMatcher 는 AntPathMatcher 를 이용하고 있다. \\
특정 pattern 그룹군을 만든후 patterns 에 등록하고 그에 해당하는 후처리 로직을 정의하여 등록할 수 있는 구조이다. \\
=== Handler 구현체 ===
먼저 클래스에 대한 이해가 필요하다. 앞단에서 간단하게 설명을 했지만 다시 정리 하자면\\
Exception 발생시 AOP pointcut "After-throwing" 걸려 ExceptionTransfer 클래스의 transfer 가 실행된다.\\
transfer 메소드는 ExceptionHandlerManager 의 run 메소드를 실행한다. 아래는 구현예로 DefaultExceptionHandleManager 코드이다.\\
**(구현시 필수사항) 상위클래스는 AbsExceptionHandleManager(또는 AbstractExceptionHandleManager)이고 인터페이스는 ExceptionHandlerService 이다.** \\
구현되는 메소드는 run(Exception exception) 인 것을 확인할 수 있다. \\
** DefaultExceptionHandleManager.java**
public class DefaultExceptionHandleManager extends AbstractExceptionHandleManager implements ExceptionHandlerService {
@Override
public boolean run(Exception exception) throws Exception {
log.debug(" DefaultExceptionHandleManager.run() ");
// 매칭조건이 false 인 경우
if (!enableMatcher()) {
return false;
}
for (String pattern : patterns) {
log.debug("pattern = " + pattern + ", thisPackageName = " + thisPackageName);
log.debug("pm.match(pattern, thisPackageName) =" + pm.match(pattern, thisPackageName));
if (pm.match(pattern, thisPackageName)) {
for (ExceptionHandler eh : handlers) {
eh.occur(exception, getPackageName());
}
break;
}
}
return true;
}
}
DefaultExceptionHandleManager 클래스는 목적이 설정을 통해 등록된 handler 클래스를 실행하는 것이다. \\
그렇다면 handler 클래스는 어떻게 구현되는지 알아보도록 하자. \\
실제로 Exception 후처리 로직은 handler 이다. 아래 클래스는 EgovServiceExceptionHandler 이다. \\
아래 코드는 log 만 남기고 있지만 실제로는 메일이나 다른 로직을 실행하도록 호출 할 수 있다. \\
** EgovServiceExceptionHandler.java**
public class EgovServiceExceptionHandler implements ExceptionHandler {
protected Log log = LogFactory.getLog(this.getClass());
public void occur(Exception ex, String packageName) {
log.debug(" EgovServiceExceptionHandler run...............");
try {
log.debug(" sending a alert mail is completed ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
=== Customizable Handler 등록 ===
시나리오 : CustomizableHandler 클래스를 만들어 보고 sample 패키지에 있는 Helloworld 클래스 Exception 시에 CustomizableHandler 를 실행한다.\\
먼저 CustomHandler 클래스를 아래와 같이 만든다.\\
ExceptionHandleManager 에서는 occur 메소드를 실행한다. \\
**Handler 구현체는 반드시 (필수사항) ExceptionHandler Interface를 갖는다. **
**CustomizableHandler.java**
public class CustomizableHandler implements ExceptionHandler {
protected Log log = LogFactory.getLog(this.getClass());
public void occur(Exception ex, String packageName) {
log.debug(" CustomHandler run...............");
try {
log.debug(" CustomHandler 실행 ... ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
CustomizableHandler 의 등록을 해보도록 하겠다.\\
역시서 주의해야 하는 부분은 patterns 에 sample 패키지에 있는 Helloworld 클래스 를 지정해주어야 한다. \\
**sample.Helloworld
이런식으로 여러개의 Handler를 등록해줄 수 있다.
==== leaveaTrace 설정 및 설명=====
----
Exception 이거나 Exception 이 아닌 경우에 Trace 후처리 로직을 실행 시키고자 할 때 사용한다.\\
설정하는 기본적인 구조는 Exception 후처리 하는 방식과 같다. 설정파일이 context-common.xml 이다.\\
DefaultTraceHandleManager 에 TraceHandler를 등록하는 형태로 설정된다.\\
=== Bean 설정 ===
...
*
...
=== TraceHandler 확장 개발 Sample ===
** Interface TraceHandler를 아래와 같이 implements 한다. **
package egovframework.rte.fdl.cmmn.trace.handler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class DefaultTraceHandler implements TraceHandler {
public void todo(Class clazz, String message) {
//수행하고자 하는 처리로직을 넣는 부분...
System.out.println(" log ==> DefaultTraceHandler run...............");
}
}
=== leaveaTrace 코드상 발생 Sample ===
사용방법을 다시 상기 해보면 아래와 같다. \\
메세지키(message.trace.msg) 를 이용하여 메세지 정보를 넘겨 Handler 를 실행한다. \\
public CategoryVO selectCategory(CategoryVO vo) throws Exception {
CategoryVO resultVO = categoryDAO.selectCategory(vo);
try {
//강제로 발생한 ArithmeticException
int i = 1 / 0;
} catch (ArithmeticException athex) {
//Exception 을 발생하지 않고 후처리 로직 실행.
leaveaTrace("message.trace.msg");
}
return resultVO;
}
===== 참고자료 =====
* [[http://www.onjava.com/pub/a/onjava/2006/01/11/exception-handling-framework-for-j2ee.html?page=1|exception-handling-framework-for-j2ee]]
* Effective Java (Joshua Bloch) : Chapter 8 예외처리