zoukankan      html  css  js  c++  java
  • [转载] Logging Standard Exceptions with Spring AOP

    Logging Standard Exceptions with Spring AOP

    Posted by Tejus Parikh on May 18, 2011

    One of the challenges of working on a large system with multiple developers is the management and handling of application errors and exceptions. Often, developers get frustrated with managing typed exceptions and all interfaces either throw or catch Exception. Another common approach is to change all exceptions to RuntimeException to avoid cluttering interfaces. An alternative approached is described in this paper by Andy Longshaw. His approach breaks exceptions into two distinct hierarchies, domain and system. Domain errors caused by logical faults in the application, such as a zero being passed as a divisor to a function. System errors are errors caused through the interaction with other components, like a network timeout when attempting to communicate with the database. Both exception types are checked exceptions, which means they must be caught and handled by each layer of the application. He presents guidelines on when and at which layer each type of exception should be logged. If you are using Java the obvious drawback of using checked exceptions everywhere is that each layer will be filled with code that looks like the following:

        try {
    
            service.doApiCall();
    
        } catch(DomainException e) {
    
            log.error("Domain exception occurred", e);
    
        } catch(SystemException e) {
    
            log.error("System exception occurred", e);
    
        }
    
    

    The duplication of handling of api exceptions can easily be handled with a custom annotation and Spring AOP. The first step is to create the Boundary logging annotation. This annotation describes where exceptions should be logged.

        @Retention(value = RetentionPolicy.RUNTIME)
    
        @Target(value = {ElementType.METHOD})
    
        public @interface BoundaryLogger {
    
        }
    
    

    Next, we need to create the interceptor. Along with just logging exceptions, I also choose to log the api calls. There are a few steps to creating an Aspect that can be used by Spring-AOP. First added the @Aspect annotation to the class declaration.

        @Service    // make this available as a spring bean
    
        @Aspect     // tell spring this class is an aspect
    
        public class BoundaryLoggingInterceptor {
    
    

    Next, create a method that tells the Aspect to do something before the underlying method, annotated with @BoundaryLogger, is called. In this example, it’s to log the method invocation.

        @Before("@annotation(net.vijedi.springlogging.interceptor.BoundaryLogger)")
    
        public void logInvocation(JoinPoint jp) {
    
    

    Similarly, triggering the aspect at method end can be handled with:

        @AfterReturning(
    
                pointcut = "@annotation(net.vijedi.springlogging.interceptor.BoundaryLogger)",
    
                returning = "retVal")
    
        public void logComplete(JoinPoint jp, Object retVal) {
    
    

    The one we are especially interested in for this purposes of this blog post is exception logging. This is the entire method for logging exceptions:

        @AfterThrowing(
    
                pointcut = "@annotation(net.vijedi.springlogging.interceptor.BoundaryLogger)",
    
                throwing = "ex"
    
        )
    
        public void processException(JoinPoint jp, Throwable ex) throws SystemException, DomainException {
    
            if(ex instanceof SystemException) {
    
                // System exceptions were logged at source
    
                // do not log the exception, just the return
    
                logReturn(jp, getLog(jp));
    
                throw (SystemException) ex;
    
            } else if(ex instanceof DomainException) {
    
                logException(jp, ex);
    
                throw (DomainException) ex;
    
            } else {
    
                logException(jp, ex);
    
                throw new DomainException(ex);
    
            }
    
    
    
        }
    
    

    The logException method is very simple:

        private void logException(JoinPoint jp, Throwable ex) {
    
            Log log = getLog(jp);
    
            log.error(ex.getMessage(), ex);
    
            logReturn(jp, log);
    
        }    
    
    

    How the logger is obtained is very important for accurate logging. Otherwise, it will appear that all logging messages are coming from the interceptor and not from the underlying method. Along with the confusion this could cause, it will also make it harder to use automatic log analyzers. However, it is very easy to get a logger in the context of the underlying class.

        protected Log getLog(JoinPoint jp) {
    
            return LogFactory.getLog(jp.getTarget().getClass());
    
        }
    
    

    Once the Aspect has been created, the final step is to tell spring what to do when it encounters the annotation @BoundaryLogger. There are four steps, tell spring to use annotations to configure the environment, to scan the packages the annotations are in, and to create the aop environment.

        

    This is all that’s need to use annotations for logging at the tier boundaries. The complete code for the example is available at my Spring Boundary Logging repo on Github.

    - See more at: http://www.tejusparikh.com/2011/logging-standard-exceptions-with-spring-.html#sthash.MNPx8RnM.dpuf

  • 相关阅读:
    剑指offer--26.顺时针打印矩阵
    剑指offer--25.二叉树的镜像
    剑指offer--24.树的子结构
    剑指offer--23.合并两个排序的链表
    剑指offer--22.反转链表
    剑指offer--21.链表中倒数第k个结点
    剑指offer--20.矩形覆盖
    剑指offer--19.重建二叉树
    剑指offer--18.从尾到头打印链表
    剑指offer--17.第一个只出现一次的字符
  • 原文地址:https://www.cnblogs.com/yuxiaoqi/p/4617882.html
Copyright © 2011-2022 走看看