spring aop实现日志收集
概述
详细
代码下载:http://www.demodashi.com/demo/10185.html
使用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 日志方案》
注:本文著作权归作者,由demo大师(http://www.demodashi.com)宣传,拒绝转载,转载需要作者授权
spring aop实现日志收集相关推荐
- spring AOP切面日志
spring AOP切面日志 导入依赖 <properties><fastjson.version>1.2.49</fastjson.version> </p ...
- Spring AOP 的日志管理实现
2019独角兽企业重金招聘Python工程师标准>>> 在学习Spring框架的历程中,最重要的是要理解Spring的IOC和AOP了,不但要学会怎么用,最好是知道它是怎么实现的,通 ...
- Spring AOP的日志记录
现在的项目是Spring+MyBatis,前段时间项目经理让我干了一个活,就是给所有的controller里的所有方法加上日志记录的代码,其实没有多少,也就300来个方法,也没有抱怨什么,一边打着瞌睡 ...
- spring Aop实现日志
作用:日志用来记录项目的动态,以便于项目出问题时排查解决 这里用到spring的两大核心之一---------->aop 这版讲到的日志是作用在方法的,通过aop来指定某些方法以完成在执行方法前 ...
- spring:利用Spring AOP 使日志输入与方法分离
对方法进行日志输出是一种很常见的功能.传统的做法是把输出语句写在方法体的内部,在调用该方法时,用输入语句输出信息来记录方法的执行! 1.先写一个普通类: package com.importnew;p ...
- Spring AOP进行日志记录,管理
http://blog.csdn.net/sd0902/article/details/8393770 转载于:https://my.oschina.net/liangzhenghui/blog/84 ...
- 使用Spring AOP进行面向方面的编程
面向方面的编程(AOP)是指将辅助功能或支持功能与主程序的业务逻辑隔离开来的编程范例. AOP是用于分离横切关注点的有前途的技术,这在面向对象的编程中通常很难做到. 以此方式增加了应用程序的模块化,并 ...
- Spring AOP与IOC
Spring AOP实现日志服务 pom.xml需要的jar <dependency><groupId>org.apache.commons</groupId>&l ...
- Spring AOP与IOC以及自定义注解
Spring AOP实现日志服务 pom.xml需要的jar <dependency><groupId>org.apache.commons</groupId>&l ...
最新文章
- 一个老产品的心路历程
- Spring Mybatis实例SqlSessionDaoSupport混用xml配置和注解
- python 遍历目录或文件
- 已启用 https://chai2010.cn, 欢迎访问!
- linux测试dvi接口,液晶显示器DVI接口及测试规范.pdf
- OpenCV基本函数使用--Python
- C#中的多线程:如何将函数名称传递给另一个函数来启动新线程?
- poj 2479 Maximum sum(递推)
- 【数字图像处理5.3】SLIC算法 超像素分割(无监督聚类方式)python
- 在线文本加密解密工具
- 远程服务器停止运行怎么回事,远程桌面连接已停止工作解决方法
- ICE for Linux
- 计算机的色彩在哪调整w10,win10电脑色彩太冷怎么调节屏幕色彩
- Linux工作中必知必会的命令总结
- C语言 会员管理系统
- arch Linux 无线网,archlinux 连接无线网络
- 【5】windows本地安装数据库
- Struts2 注解开发实现简单的增删改查,超详细教程
- matlab fitctree 原理,电力窃漏电用户自动识别.PDF
- ipvs命令~创建VS/DR模式集群
热门文章
- wxpython 基本的控件 (按钮)
- sqlyong导出sql没有数据_sqlyog怎么导入外部数据库-sqlyog导入数据库的方法 - 河东软件园...
- 无源波分和彩光模块_5G前传WDM解决方案,无源波分和彩光模块
- STC51-C51基础知识
- STM32 DMA传输
- MySQL C 语言应用程序接口开发教程
- Linux-kernel网桥代码分析(二)
- 嵌入式Linux系统编程学习之五gcc/g++编译器
- Linux中sudo命令设置,Linux下sudo命令的配置与使用方法
- mysql 设置utf8mb4_mysql配置utf8_mb4