복붙노트

[SPRING] Spring AOP - catch 블록에서 조언 호출

SPRING

Spring AOP - catch 블록에서 조언 호출

목적 : 비즈니스 논리를 실행하는 동안 예외가 발생할 때마다 관리자에게 전자 메일을 보냅니다.

지금까지 나는 타겟 메소드에서 예외가 발생했을 때 "괜찮은 조언을 던져"왔으며 실행되었다.

이것은 나를 위해 잘 작동했을 수도 있지만 요청 속성과 다음 페이지를 설정하는 측면에서 몇 가지 추가 처리를해야합니다. 객체를 정적으로 만들어서 대상 클래스의 객체를 조언과 공유하는 것이 좋은 생각이라고 생각하지 않습니다. 코드 시나리오는 다음과 같습니다.

try{
   //normal processing
} catch (AuthenticationException ae) {
   ae.printStackTrace();
   req.setAttribute("msg", ae.getMessage());

   //execute advice at this point

   return loginPage;
}

Pls. 조언을 실행하고 이에 따라 솔루션을 제안하고 싶은 시점을 확인하십시오.

친애하는

해결법

  1. ==============================

    1.Spring AOP와는 반대로 AspectJ 전체를 사용하지 않기를 원한다는 것을 알고있다. (BTW, 왜 많은 사람들이 그렇게 두려워하는지 궁금합니다.) 어쨌든 AspectJ에서는 handler () pointcut을 사용하여 예외 핸들러 실행 (= catch 블록)을 가로 채기가 정말 쉽습니다. 그러나 한 가지 제한이 있습니다 : before () advice만으로 작동하고 after () 또는 around ()는 작동하지 않습니다. 이것은 컴파일러의 한계 때문입니다. 예외 처리기의 JVM 바이트 코드를 살펴보면 처리기 블록의 끝을 감지 할 수있는 방법이 없다는 것을 알 수 있습니다. 어쨌든, 그 개념이 원래의 질문과 관련되어 있기 때문에, 나는 그것이 어떻게 행해졌는지 여기에서 보여주고 싶습니다. 나는 작은 드라이버 응용 프로그램과 매우 간단한 측면을 만들었습니다.

    Spring AOP와는 반대로 AspectJ 전체를 사용하지 않기를 원한다는 것을 알고있다. (BTW, 왜 많은 사람들이 그렇게 두려워하는지 궁금합니다.) 어쨌든 AspectJ에서는 handler () pointcut을 사용하여 예외 핸들러 실행 (= catch 블록)을 가로 채기가 정말 쉽습니다. 그러나 한 가지 제한이 있습니다 : before () advice만으로 작동하고 after () 또는 around ()는 작동하지 않습니다. 이것은 컴파일러의 한계 때문입니다. 예외 처리기의 JVM 바이트 코드를 살펴보면 처리기 블록의 끝을 감지 할 수있는 방법이 없다는 것을 알 수 있습니다. 어쨌든, 그 개념이 원래의 질문과 관련되어 있기 때문에, 나는 그것이 어떻게 행해졌는지 여기에서 보여주고 싶습니다. 나는 작은 드라이버 응용 프로그램과 매우 간단한 측면을 만들었습니다.

    import java.util.Random;
    import javax.naming.AuthenticationException;
    
    public class Application {
        public static void main(String[] args) {
            Application app = new Application();
            System.out.println(app.foo(1, "two", 3d));
            System.out.println(app.bar("one", 2d, 3));
            System.out.println(app.zot(1d, 2, "three"));
        }
    
        public String foo(int i, String string, double d) {
            try {
                if (new Random().nextBoolean())
                    throw new AuthenticationException("wrong password");
            }
            catch (AuthenticationException e) {
                return "return value from catch block";
            }
            return "normal return value";
        }
    
        public String bar(String string, double d, int i) {
            try {
                if (new Random().nextBoolean())
                    throw new IllegalArgumentException("I don't like your arguments");
            }
            catch (IllegalArgumentException e) {
                return "return value from catch block";
            }
            return "normal return value";
        }
    
        public String zot(double d, int i, String string) {
            try {
                int n = 2/0;
            }
            catch (Throwable t) {
                return "return value from catch block";
            }
            return "normal return value";
        }
    }
    

    보시다시피, 메소드 foo와 bar는 ca의 무작위 값을 기반으로 예외를 발생시킵니다. 모든 경우의 50 % 인 반면 zot은 항상 0으로 나누기 예외를 throw합니다. 따라서 출력은 실행마다 다릅니다.

    그렇다면 모든 예외가 조용히 삼켜지고 기록되지 않으면 어떻게되는지 알 수 있습니까? 이렇게 :

    import java.util.logging.Logger;
    
    public aspect ExceptionLoggingAspect {
        final Logger log = Logger.getLogger(ExceptionLoggingAspect.class.getName());
    
        before(Throwable t) : handler(Throwable+) && args(t) {
            log.warning(thisJoinPointStaticPart + "  ->  " + t);
        }
    }
    

    이것은 매우 간단하고 우아하며 응용 프로그램 전체에서 작동합니다. 다음은 몇 가지 테스트 결과입니다.

    Apr 6, 2013 12:15:43 PM ExceptionLoggingAspect ajc$before$ExceptionLoggingAspect$1$3d90b181
    WARNING: handler(catch(AuthenticationException))  ->  javax.naming.AuthenticationException: wrong password
    return value from catch block
    Apr 6, 2013 12:15:43 PM ExceptionLoggingAspect ajc$before$ExceptionLoggingAspect$1$3d90b181
    WARNING: handler(catch(IllegalArgumentException))  ->  java.lang.IllegalArgumentException: I don't like your arguments
    return value from catch block
    Apr 6, 2013 12:15:43 PM ExceptionLoggingAspect ajc$before$ExceptionLoggingAspect$1$3d90b181
    WARNING: handler(catch(Throwable))  ->  java.lang.ArithmeticException: / by zero
    return value from catch block
    

    조언에서 당신은 더 많은 것을 할 수 있습니다. 이것에 액세스하고 일부 속성을 읽고 / 업데이트하십시오.

  2. ==============================

    2.좋습니다, Spring in Action과 같은 참고 도서를 살펴본 후 Java 코드의 임의의 지점에서 스프링 조언을 호출 할 수있는 방법이 없음을 알게되었습니다. Spring in Action 책은 포인트 컷에 대한 미세 입자 제어를 위해 AspectJ를 살펴볼 것을 권장한다.

    좋습니다, Spring in Action과 같은 참고 도서를 살펴본 후 Java 코드의 임의의 지점에서 스프링 조언을 호출 할 수있는 방법이 없음을 알게되었습니다. Spring in Action 책은 포인트 컷에 대한 미세 입자 제어를 위해 AspectJ를 살펴볼 것을 권장한다.

    AspectJ 추가를 피하기 위해 다른 사람들을 도우며 소중한 시간을 절약 할 수있는 다음 솔루션을 발견했습니다.

    1) 예외 발생시에만 advice를 호출하려는 메소드에 Around advice를 사용하십시오. 필자의 경우처럼, 예외가 발생했을 때 전자 메일 알림을 보내고 catch 블록에서 빠져 나오고 싶습니다. 기본적으로 조언을하기 전에 catch 블록에서 일부 처리를 수행하려고했습니다.

    2) Around advice를 사용할 때 메소드의 인자로 target 객체의 멤버 변수를 읽을 수있다. 조언과 함께 일부 데이터를 공유하고 싶다면, 또한 방법 중 하나입니다. 제 경우에는 전자 메일 제목과 본문에 대한 대상 개체의 세부 정보가 필요했습니다.

    주변 조언을위한 코드 :

    import java.lang.reflect.Method;
    import org.springframework.aop.AfterReturningAdvice;
    
    public class NotificationAdvice implements AfterReturningAdvice  {
        public void afterReturning(Object returnValue, Method method,
                Object[] args, Object target) throws Throwable {
                System.out.println(returnValue);
                System.out.println(method.getName());
                System.out.println(args[0]);
                System.out.println(((target)target).flag);
        }
    }
    

    이 접근법에 대한 피드백 / 질문을 공유하십시오.

  3. ==============================

    3.AFAIK 거기에 대한 pointcut 표현이 ...

    AFAIK 거기에 대한 pointcut 표현이 ...

    로거가 필요한 것을 수행하도록 구성하는 것을 고려해야합니다. Replace ae.printStackTrace (); logger.warn (ae) (콘솔에 스택 트레이스를 인쇄하는 것은 아주 나쁜 습관입니다.)과 같이 로깅 도구의 전자 메일 보내기 애펜더 중 하나를 구성하십시오. log4j 또는 logback의 SMTPAppender. 또한 구성을 쉽게하기 위해 비즈니스 전용 로거를 사용할 수 있습니다.

    여기서 aspect를 실제로 사용하고 싶다면 afterThrowing advices를 사용하기 위해 적어도 하나의 메소드를 버블 링해야하는 모든 비즈니스 예외를 기대해야합니다.

  4. ==============================

    4.늘어나는만큼 내 이해는 왜 AuthenticationException 비즈니스 로직 코드에서 throw됩니다 말한다. 당신이 정말로 원톱을 사용하고 싶다면 컷 비즈니스 관심을 멀리 크로스 커팅에서. 귀하의 경우에는 비즈니스 로직에서 AuthenticationException 코드를 추출 할 수 있습니다. 비즈니스 로직 조작을 시작하기 전에 aop.for 예제를 적용하십시오

    늘어나는만큼 내 이해는 왜 AuthenticationException 비즈니스 로직 코드에서 throw됩니다 말한다. 당신이 정말로 원톱을 사용하고 싶다면 컷 비즈니스 관심을 멀리 크로스 커팅에서. 귀하의 경우에는 비즈니스 로직에서 AuthenticationException 코드를 추출 할 수 있습니다. 비즈니스 로직 조작을 시작하기 전에 aop.for 예제를 적용하십시오

    public class SecurityInterceptor extends HandlerInterceptorAdapter{
    
    
    
        //before the actual handler will be executed
        public boolean preHandle(HttpServletRequest request, 
            HttpServletResponse response, Object handler)
            throws Exception {
    
    
            // check here possible case for exception from request .If exception throw yours custom exception before executing business logic
    
    
        }
    
        //after the handler is executed
        public void postHandle(
    
            }
        }
    }
    

    맞춤 예외

    public class Handler
            implements HandlerExceptionResolver
        {
    
            public Handler()
            {
            }
    
            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            {
                if(ex instanceof AuthenticationException))
                {
                     ModelAndView test = new ModelAndView("errorpage1jsppage");
    return test;
                } else
                if(ex instanceof ErrorType2Exception))
                {
                     ModelAndView test1 = new ModelAndView("errorpage2jsppage");
    return test1
                }
            }
        }
    
  5. from https://stackoverflow.com/questions/15473725/spring-aop-invoking-advice-from-catch-block by cc-by-sa and MIT license