Spring AOP - Logging, Exception 구현

2010. 8. 19. 00:48plming/Java - Spring

1. Target
   Logging, Exception등을 제외한 단지 비즈니스 로직만을 포함하고 있어야 한다.

   ※ AOP를 적용한다고 해서 일정한 패턴이 없는 모든 Logging을 제거할 수는 없다.  해당 메써드내에서만 추가되는 Logging 메시지 같은 경우에는 과거와 같은 방식으로 구현할 수 밖에 없다.

       애플리케이션을 개발할 때 애플리케이션 개발을 위하여 세운 정책(이것이 Aspect이다.)은 일정한 패턴이 있기 때문에 이를 Advice로 구현하는 것이 가능하지만 일정한 패턴없이 구현되는 부분에 대해서는 과거와 같은 방식으로 개발할 수 없다는 것을 의미한다.


2. Advice
   Target 클래스에 추가적인 기능을 지원하기 위한 목적으로 사용되는 것.

   - Logging 처리를 담당할 Advice = Spring의 Around Advice에 해당

 import org.aopalliance.intercept.MethodInterceptor;
 import org.aopalliance.intercept.MethodInvocation;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;

 public class UserLoggingAdvice implements MethodInterceptor {
     protected final Log logger = LogFactory.getLog(getClass());

     public Object invoke(MethodInvocation invocation) throws Throwable {
         String className = invocation.getThis().getClass().getName();

         if (logger.isDebugEnabled()) {
             logger.debug(className + "." + invocation.getMethod().getName() + "()"
                     + " 시작!!");
             Object[] args = invocation.getArguments();
             if ((args != null) && (args.length > 0)) {
                 for (int i = 0; i < args.length; i++) {
                     logger.debug("Argument[" + i + "] : " + args[i]);
                 }
             }
         }

         //Target 클래스의 메써드를 실행한다.
         Object retVal = invocation.proceed();

         if (logger.isDebugEnabled()) {
             logger.debug(className + "." + invocation.getMethod().getName() + "()"
                     + " 종료!!");
         }

         return retVal;
     }
 }


   - Unchecked Exception 처리를 담당할 Advice

 import org.springframework.aop.ThrowsAdvice;

 public class EmailNotificationThrowsAdvice implements ThrowsAdvice {

     public void afterThrowing(RuntimeException ex) throws Throwable {
         if (logger.isDebugEnabled()) {
             logger.debug("afterThrowing() 시작");
             logger.debug("Caught : " + ex.getClass().getName());
         }
         mailSender.sendMessage(ex);
         if (logger.isDebugEnabled()) {
             logger.debug("afterThrowing() 종료");
         }
     }
 }



   - Spring Framework에서 지원하는 5가지 Advice
 Before Advice
 : MethodBeforeAdvice
 Target 클래스의 메소드가 실행되기 전에 기능을 추가하고 싶을 때 사용
 After Returning Advice
 : AfterReturningAdvice.afterReturning()
 Target 클래스의 메소드 실행이 완료된 다음 후처리 작업이 필요할 경우에 사용
 Around Advice  Target 클래스의 메소드, 인자에 대한 정보뿐만 아니라 Target 클래스의 메소드에 대한 직접적인 제어가 가능
 Throws Advice  Target 클래스의 메소드 내에서 Exception이 발생했을 때 적용
 afterThrowing( DataAccessException e )와 같이 메소드를 추가하여 사용
 Introduction Advice  Target 클래스에 완전히 새로운 기능을 추가하는 것이 가능


3. Pointcut 과 Advisor
   Pointcut은 Target 클래스와 Advice가 결합(Weaving)될 때 둘 사이의 결합 규칙을 정의하는 것.

 public class UserLoggingPointcut extends StaticMethodMatcherPointcut {

     public boolean matches(Method method, Class cls) {
         if( "addUser".equals(method.getName()) ){
             return true;
         }
         return false;
     }

     public ClassFilter getClassFilter() {
         return new ClassFilter() {
             public boolean matches(Class cls) {
                 return (cls == UserServiceImpl.class) || (cls == MySQLUserDAO.class);
             }
         };
     }
 }


 public class LoggingUserServiceTest extends TestCase {

     public void testLoginWithPointcut() throws Exception {
         ::::
         UserService target = new UserServiceImpl();
         target.setUserDAO(mock);

         ProxyFactory pf = new ProxyFactory();

         Pointcut loggingPC = new UserLoggingPointcut();
         Advisor loggingAdvisor = new DefaultPointcutAdvisor(loggingPC, new UserLoggingAdvice());
         pf.addAdvisor(loggingAdvisor);

         pf.setTarget(target);

         UserService userService = (UserService) pf.getProxy();


Advisor 클래스는 AOP의 Aspect와 같은 개념으로 Advice와 Pointcut이 결합된 것
Advisor를 생성하기 위해서는 Advice와 Pointcut이 필요

- Spring 프레임워크에서 지원하는 일곱가지 Pointcut

 1. StaticMethodMatcherPointcut
    Target 클래스의 정적인 정보(클래스 이름, 메소드 이름)를 기반으로 Pointcut을 만들고자 할 때 사용
    matches(Method method, Class targetClass) 추상메소드를 구현해야 한다.

 2. DynamicMethodMatcherPointcut
    Target 클래스의 정적인 정보를 포함하여 동적인 정보(메소드 호출 시 전달되는 인자 값)를 기반으로 Pointcut을 만들고자 할 때 사용
    matches(Method method, Class targetClass, Object[] args) 추상메소드를 구현해야 한다.

 ※ 나머지 Pointcut은 모두 구현된 클래스로 추가 구현없이 사용 가능하다.

 3. Perl5RegexpMethodPointcut, JdkRegexpMethodPointcut
    정규표현식을 이용하는 것이 가능
    Perl5 형식의 정규표현식, JDK에서 지원하는 정규표현식을 각각 지원

 4. NameMatchMethodPointcut
    메써드 이름에 해당하는 메써드에 대해서만 Advice가 적용되도록 지원

 5. ComposablePointcut
    두개 이상의 Pointcut을 결합하기 위하여 사용

 6. ControlFlowPointcut
    Target 클래스 메써드 하위에서 특정 패턴에 일치하는 메써드에 대해서만 Advice를 적용하도록 지원



[출처] http://www.javajigi.net/pages/viewpage.action?pageId=7208963
[출처] Spring 프레임워크 워크북

'plming > Java - Spring' 카테고리의 다른 글

Spring Transaction  (0) 2010.08.22
Spring - 빈 설정 파일 관리  (0) 2010.08.22
Spring AOP (Aspect Oriented Programming)  (0) 2010.08.19
Spring - 테스트 전략  (0) 2010.08.17
ANT 사용 시 한글 Properties 파일처리  (0) 2010.08.17