spring aop实现日志收集
技术:spring 4.3.3
概述
使用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后,运行的界面如下:
用户名 1001 密码 123
登陆后,修改密码,则看到eclipse控制台打印如下信息:
这样一个aop收集日志的功能了,这样的方式比直接把log写在具体的方法上要强多了,收集起来的log,可以直接写在本地,也可以接入elk方案。
接入elk方案可以参考本网站中的:《ELK + kafka 日志方案》
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码