使用Spring Aspect监视方法

时间:2019-05-23 15:30:15

标签: java spring spring-boot spring-rest spring-aspects

我想实现Spring Aspect进行日志记录。我尝试了此实现:

记录方面:

    import org.apache.commons.lang.builder.ReflectionToStringBuilder;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import javax.servlet.http.HttpServletRequest;
    import java.util.Arrays;
    import java.util.Enumeration;

    @Aspect
    @Component
    public class LoggingAspect {

        private static final String CONTROLLER_EXPRESION = "within(@org.springframework.stereotype.Controller *) && execution(* *.*(..))";
        private static final Logger log = LoggerFactory.getLogger(LoggingAspect.class);

        /**
         * Before -> Any resource annotated with @Controller annotation and all method
         * and function taking HttpServletRequest as first parameter.
         *
         * @param joinPoint
         * @param request
         */
        @Before(CONTROLLER_EXPRESION)
        public void logBefore(JoinPoint joinPoint, HttpServletRequest request) {

            log.debug("Entering in Method : {}", joinPoint.getSignature().getName());
            log.debug("Class Name :  {}", joinPoint.getSignature().getDeclaringTypeName());
            log.debug("Arguments :  {}", Arrays.toString(joinPoint.getArgs()));
            log.debug("Target class : {}", joinPoint.getTarget().getClass().getName());

            if (null != request) {
                log.debug("Start Header Section of request ");
                log.debug("Method Type : {}", request.getMethod());
                Enumeration headerNames = request.getHeaderNames();
                while (headerNames.hasMoreElements()) {
                    String headerName = headerNames.nextElement().toString();
                    String headerValue = request.getHeader(headerName);
                    log.debug("Header Name: {} Header Value : {}", headerName, headerValue);
                }
                log.debug("Request Path info : {}", request.getServletPath());
                log.debug("End Header Section of request ");
            }
        }

        /**
         * After -> All method within resource annotated with @Controller annotation.
         *
         * @param joinPoint
         * @param result
         */
        @AfterReturning(pointcut = CONTROLLER_EXPRESION, returning = "result")
        public void logAfter(JoinPoint joinPoint, Object result) {
            String returnValue = this.getValue(result);
            log.debug("Method Return value : {}", returnValue);
        }

        /**
         * After -> Any method within resource annotated with @Controller annotation and throws an exception ...Log it 
         * @param joinPoint
         * @param exception
         */
        @AfterThrowing(pointcut = CONTROLLER_EXPRESION, throwing = "exception")
        public void logAfterThrowing(JoinPoint joinPoint, Throwable exception) {
            log.error("An exception has been thrown in {} {}", joinPoint.getSignature().getName(), " ()");
            log.error("Cause : {}", exception.getCause());
        }

        /**
         * Around -> Any method within resource annotated with @Controller annotation. 
         * @param joinPoint
         * @return
         * @throws Throwable
         */
        @Around(CONTROLLER_EXPRESION)
        public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {

            long start = System.currentTimeMillis();
            try {
                String className = joinPoint.getSignature().getDeclaringTypeName();
                String methodName = joinPoint.getSignature().getName();
                Object result = joinPoint.proceed();
                long elapsedTime = System.currentTimeMillis() - start;
                log.debug("Method {}.{} () execution time :  {} ms", className, methodName, elapsedTime);

                return result;
            } catch (IllegalArgumentException e) {
                log.error("Illegal argument {} in {}()", Arrays.toString(joinPoint.getArgs()), joinPoint.getSignature().getName());
                throw e;
            }
        }

        private String getValue(Object result) {
            String returnValue = null;
            if (null != result) {
                if (result.toString().endsWith("@" + Integer.toHexString(result.hashCode()))) {
                    returnValue = ReflectionToStringBuilder.toString(result);
                } else {
                    returnValue = result.toString();
                }
            }
            return returnValue;
        }
    }

但是当我在应用服务器上部署代码时,我得到了这个错误堆栈:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut 

我要监视的控制器位于org.rest.api.server.controller.Homecontroller-Java方法句柄下。我需要指定确切的路径还是遗漏其他内容?

1 个答案:

答案 0 :(得分:0)

您的问题是由于HttpServletRequest中的额外参数logBefore引起的;方面无法绑定的。如果需要连接点的参数;最好在方面进行检查。因此,您的logBefore方法应更改为:

    @Before(CONTROLLER_EXPRESION)
    public void logBefore(JoinPoint joinPoint, HttpServletRequest request) {

        // ASPECT LOGIC
        // ...
    }

对此:

    @Before(CONTROLLER_EXPRESION)
    public void logBefore(JoinPoint joinPoint) {
        HttpServletRequest request = (HttpServletRequest)joinPoint.getArgs()[0];

        // ASPECT LOGIC
        // ...
    }

希望这会有所帮助。