zoukankan      html  css  js  c++  java
  • spring aop实现日志收集

    概述

    使用spring aop 来实现日志的统一收集功能

    详细

    使用spring aop 来实现日志的统一收集功能。

    spring aop 配置

    首先,我们定义2种注解,一种是给service用的,一种是给Controller用的。

    给service使用的aop扫描
    <aop:aspectj-autoproxy />
    
    <context:annotation-config />
    
    <context:component-scan base-package="com.demodashi">
    	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
    
    <tx:annotation-driven />
    给Controller使用的aop扫描
    <aop:aspectj-autoproxy />
    <aop:aspectj-autoproxy proxy-target-class="true" />
    
    <!-- 扫描web包,应用Spring的注解 -->
    <context:component-scan	base-package="com.demodashi">
    	<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    	<context:exclude-filter type="annotation" expression="javax.inject.Named" />
    	<context:exclude-filter type="annotation" expression="javax.inject.Inject" />
    </context:component-scan>

    java实现

    实现思路,先定义两个注解类,一个给service类用的,一个给从controller类用的,然后使用切面类,对这两个注解进行绑定监控。结果就是,当使用注解绑定某个service类或者controller类的某个方法时,这个切面类就能监控到,并且能获取到这个service方法的相关输入,输出参数等。这样,就能实现了aop日志了。

    给controller使用的注解类
    package com.demodashi.aop.annotation;
    import java.lang.annotation.*;    
        
    /**  
     *自定义注解 拦截Controller  
     */    
        
    @Target({ElementType.PARAMETER, ElementType.METHOD})    
    @Retention(RetentionPolicy.RUNTIME)    
    @Documented    
    public  @interface ControllerLogAnnotation {    
        String description()  default "";    
    }
    给service使用的注解类
    package com.demodashi.aop.annotation;
    import java.lang.annotation.*;    
        
    /**  
     *自定义注解 拦截service  
     */    
        
    @Target({ElementType.PARAMETER, ElementType.METHOD})    
    @Retention(RetentionPolicy.RUNTIME)    
    @Documented    
    public  @interface ServiceLogAnnotation {    
        
        String description()  default "";    
    }
    日志切面类
    package com.demodashi.aop;
    
    import java.lang.reflect.Method;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import com.alibaba.fastjson.JSONObject;
    import com.demodashi.aop.annotation.ControllerLogAnnotation;
    import com.demodashi.aop.annotation.ServiceLogAnnotation;
    import com.demodashi.base.UserVO;
    
    /**
     * 切点类   
     * @author xgchen
     *
     */
    @Aspect    
    @Component    
    public  class SystemLogAspect {    
        
    	public SystemLogAspect(){
    	}
    	
        //本地异常日志记录对象    
        private  static  final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);    
        
        //Service层切点    
        @Pointcut("@annotation(com.demodashi.aop.annotation.ServiceLogAnnotation)")    
        public  void serviceAspect() {
        }
        
        //Controller层切点    
        @Pointcut("@annotation(com.demodashi.aop.annotation.ControllerLogAnnotation)")    
        public  void controllerAspect() {    
        }
        
        /**  
         * 前置通知 用于拦截Controller层记录用户的操作  
         *  
         * @param joinPoint 切点  
         */
        @Before("controllerAspect()")
    	public  void doBefore4control(JoinPoint joinPoint) {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();    
            HttpSession session = request.getSession();    
            //读取session中的用户    
            UserVO user = (UserVO) session.getAttribute("USER");
            //请求的IP    
            String ip = request.getRemoteAddr();    
             try {    
                //*========控制台输出=========*//    
                System.out.println("=====control 前置通知开始=====");
                System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));    
                System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));    
                System.out.println("请求人ID:" + user.getId());
                System.out.println("请求人NAME:" + user.getName());
                System.out.println("请求IP:" + ip);    
                System.out.println("=====前置通知结束=====");    
            }  catch (Exception e) {
                //记录本地异常日志    
                logger.error("==前置通知异常==");
                logger.error("异常信息:{}", e.getMessage());    
            }
        }
        
        @Before("serviceAspect()")
        public  void doBefore4service(JoinPoint joinPoint) {
        	HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();    
            HttpSession session = request.getSession();    
            //读取session中的用户    
            UserVO user = (UserVO) session.getAttribute("USER");    
            //获取请求ip    
            String ip = request.getRemoteAddr();
            //获取用户请求方法的参数并序列化为JSON格式字符串    
            String params = "";    
             if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {    
                 for ( int i = 0; i < joinPoint.getArgs().length; i++) {    
                    params += JSONObject.toJSON(joinPoint.getArgs()[i]).toString() + ";";
                }  
            }
            try {    
                /*========控制台输出=========*/    
            	System.out.println("=====service 前置通知开始=====");
                System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));    
                System.out.println("方法描述:" + getServiceMthodDescription(joinPoint));    
                System.out.println("请求人ID:" + user.getId());
                System.out.println("请求人NAME:" + user.getName());
                System.out.println("请求IP:" + ip);
                System.out.println("请求参数:" + params);
                
            }  catch (Exception ex) {    
                //记录本地异常日志    
                logger.error("==异常通知异常==");    
                logger.error("异常信息:{}", ex.getMessage());    
            }    
        }
        
        @AfterReturning(pointcut="serviceAspect()", returning="returnValue")
        public  void after4service(JoinPoint joinPoint, Object returnValue) {
        	HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();    
            HttpSession session = request.getSession();    
            //读取session中的用户    
            UserVO user = (UserVO) session.getAttribute("USER");    
            //获取请求ip    
            String ip = request.getRemoteAddr();
            //获取用户请求方法的参数并序列化为JSON格式字符串    
            String params = "";
             if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {    
                 for ( int i = 0; i < joinPoint.getArgs().length; i++) {    
                    params += JSONObject.toJSON(joinPoint.getArgs()[i]).toString() + ";";
                }  
            }
            try {    
                /*========控制台输出=========*/    
            	System.out.println("=====service 后置通知开始=====");
                System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));    
                System.out.println("方法描述:" + getServiceMthodDescription(joinPoint));    
                System.out.println("请求人ID:" + user.getId());
                System.out.println("请求人NAME:" + user.getName());
                System.out.println("请求IP:" + ip);
                System.out.println("请求参数:" + params);
                System.out.println("返回值为:" + JSONObject.toJSON(returnValue).toString());
            }  catch (Exception ex) {    
                //记录本地异常日志    
                logger.error("==异常通知异常==");    
                logger.error("异常信息:{}", ex.getMessage());    
            }
        }
        
        /**  
         * 异常通知 用于拦截service层记录异常日志  
         *  
         * @param joinPoint  
         * @param e  
         */    
        @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")    
    	public  void doAfterThrowing(JoinPoint joinPoint, Throwable e) {    
        	HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();    
            HttpSession session = request.getSession();    
            //读取session中的用户    
            UserVO user = (UserVO) session.getAttribute("USER"); 
            //获取请求ip    
            String ip = request.getRemoteAddr();    
            //获取用户请求方法的参数并序列化为JSON格式字符串    
            String params = "";    
             if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {    
                 for ( int i = 0; i < joinPoint.getArgs().length; i++) {    
                	 params += JSONObject.toJSON(joinPoint.getArgs()[i]).toString() + ";";
                }  
            }
            try {    
                /*========控制台输出=========*/    
                System.out.println("=====异常通知开始=====");
                System.out.println("异常代码:" + e.getClass().getName());    
                System.out.println("异常信息:" + e.getMessage());    
                System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));    
                System.out.println("方法描述:" + getServiceMthodDescription(joinPoint));    
                System.out.println("请求人ID:" + user.getId());
                System.out.println("请求人NAME:" + user.getName());
                System.out.println("请求IP:" + ip);
                System.out.println("请求参数:" + params);
                
                System.out.println("=====异常通知结束=====");    
            }  catch (Exception ex) {    
                //记录本地异常日志    
                logger.error("==异常通知异常==");    
                logger.error("异常信息:{}", ex.getMessage());    
            }    
             /*==========记录本地异常日志==========*/    
            logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params);    
        
        }    
        
        
        /**  
         * 获取注解中对方法的描述信息 用于service层注解  
         *  
         * @param joinPoint 切点  
         * @return 方法描述  
         * @throws Exception  
         */    
         public  static String getServiceMthodDescription(JoinPoint joinPoint)
                 throws Exception {    
            String targetName = joinPoint.getTarget().getClass().getName();    
            String methodName = joinPoint.getSignature().getName();    
            Object[] arguments = joinPoint.getArgs();    
            Class targetClass = Class.forName(targetName);    
            Method[] methods = targetClass.getMethods();    
            String description = "";    
             for (Method method : methods) {    
                 if (method.getName().equals(methodName)) {    
                    Class[] clazzs = method.getParameterTypes();    
                     if (clazzs.length == arguments.length) {    
                        description = method.getAnnotation(ServiceLogAnnotation. class).description();    
                         break;    
                    }    
                }    
            }    
             return description;    
        }    
        
        /**  
         * 获取注解中对方法的描述信息 用于Controller层注解  
         *  
         * @param joinPoint 切点  
         * @return 方法描述  
         * @throws Exception  
         */    
         public  static String getControllerMethodDescription(JoinPoint joinPoint)  throws Exception {    
            String targetName = joinPoint.getTarget().getClass().getName();    
            String methodName = joinPoint.getSignature().getName();    
            Object[] arguments = joinPoint.getArgs();    
            Class targetClass = Class.forName(targetName);    
            Method[] methods = targetClass.getMethods();    
            String description = "";    
             for (Method method : methods) {    
                 if (method.getName().equals(methodName)) {    
                    Class[] clazzs = method.getParameterTypes();    
                     if (clazzs.length == arguments.length) {    
                        description = method.getAnnotation(ControllerLogAnnotation. class).description();    
                         break;    
                    }    
                }    
            }    
             return description;    
        }    
    }
    aop使用

    就是将注解绑定到具体的service方法上面,或者control方法,如下所示:

    @ServiceLogAnnotation(description = "修改密码")
    @Override
    public UserVO changePassword(UserVO vo, String newPassword) {
    	vo.setPassword(newPassword);
    	return vo;
    }
    @ResponseBody
    @RequestMapping("/editPassword.do")
    @ControllerLogAnnotation(description = "接受修改密码的请求")
    public Map changePassword(ModelMap modelMap, HttpServletRequest request,
    		HttpServletResponse response) throws IOException {
    	String message = null;
    	String result = null;
    	Object vo = request.getSession().getAttribute("USER");
    	if (vo == null) {
    		message = "操作失败:对象不能为空!";
    	} else if (StringUtils.isBlank(request.getParameter("newPassword"))) {
    		message = "新登陆密码不能为空!";
    	}
    	if (message == null) {
    		try {
    			userApplication.changePassword((UserVO)vo, request.getParameter("newPassword"));
    			message = "修改成功!";
    			result = ConstantBean.SUCCESS;
    		} catch (Exception e) {
    			message = e.getMessage();
    			result = ConstantBean.SYSERR;
    		}
    	} else {
    		result = ConstantBean.SYSERR;
    	}
    	
    	return toMap("data", message, "result", result);
    }

    运行起来

    首把demo导入到eclipse后,运行的界面如下:

    image.png

    用户名 1001 密码 123

    登陆后,修改密码,则看到eclipse控制台打印如下信息:

    image.png

    这样一个aop收集日志的功能了,这样的方式比直接把log写在具体的方法上要强多了,收集起来的log,可以直接写在本地,也可以接入elk方案。

    接入elk方案可以参考本网站中的:《ELK + kafka 日志方案》

    注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

  • 相关阅读:
    开题
    kafka介绍原理
    xxl-job
    多线程使用
    基础
    linux命令
    oracle id 自增
    feign调用远程服务 并传输媒体类型
    复杂sql mybatis查询
    开源easyExcel应用
  • 原文地址:https://www.cnblogs.com/demodashi/p/8458078.html
Copyright © 2011-2022 走看看