• [转载] 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

  • 相关阅读:
    数据库范式
    java String.split()用法
    1.4 IoC控制反转
    利用shrinkwrap锁定依赖版本
    清晨开启电脑自动拉取项目更新
    JS如何获取屏幕、浏览器及网页高度宽度?
    Navigator 对象,能够清楚地知道浏览器的相关信息
    iconfont 转换为图标字体
    VS code的搜索、替换与正则替换
    点九图制作方法
  • 原文地址:https://www.cnblogs.com/yuxiaoqi/p/4617882.html
Copyright © 2020-2023  润新知