Spring AOP 系统日志记录
AOP是Aspect Oriented Programming的缩写,意思是面向方面编程,AOP实际是GoF设计模式的延续
关于Spring AOP的一些术语
- 切面(Aspect):在Spring AOP中,切面可以使用通用类或者在普通类中以@Aspect 注解(@AspectJ风格)来实现
- 连接点(Joinpoint):在Spring AOP中一个连接点代表一个方法的执行
- 通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括"around"、"before”和"after"等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链
- 切入点(Pointcut):定义出一个或一组方法,当执行这些方法时可产生通知,Spring缺省使用AspectJ切入点语法。
通知类型
- 前置通知(@Before):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)
- 返回后通知(@AfterReturning):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回
- 抛出异常后通知(@AfterThrowing):方法抛出异常退出时执行的通知
- 后通知(@After):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)
- 环绕通知(@Around):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型,环绕通知可以在方法调用前后完成自定义的行为,它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行
@AspectJ风格的AOP配置
Spring AOP配置有两种风格:
- XML风格 = 采用声明形式实现Spring AOP
- AspectJ风格 = 采用注解形式实现Spring AOP
创建日志记录表(MySQL)
CREATE TABLE `t_log` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `userid` bigint(20) unsigned NOT NULL, `createdate` datetime NOT NULL COMMENT '创建日期', `content` varchar(8000) NOT NULL DEFAULT '' COMMENT '日志内容', `operation` varchar(250) NOT NULL DEFAULT '' COMMENT '用户所做的操作', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
日志记录POJO类:
package com.hz.yiliao.orm; import java.io.Serializable; import java.util.Date; /** * 系统日志 * @author Administrator * */ public class Log implements Serializable{ private static final long serialVersionUID = -7372303516713218870L; private Long id;// private Long userId;// private Date createDate;//创建日期 private String content;//日志内容 private String operation;//用户所做的操作 //get set方法省略,自己生成 }
日志记录Mapper接口与XML配置文件:
package com.hz.yiliao.dao; import java.util.List; import java.util.Map; import com.hz.yiliao.orm.Log; /** * 系统日志接口 * @author Administrator * */ public interface LogMapper { /** * 新增 * @param log */ public void insert(Log log); }
LogMapper.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.hz.yiliao.dao.LogMapper"> <resultMap type="com.hz.yiliao.orm.Log" id="LogMapper"> <id property="id" column="id"/> <result property="userId" column="userid" /> <result property="createDate" column="createdate" /> <result property="content" column="content" /> <result property="operation" column="operation" /> </resultMap> <sql id="LogSQL"> userid,createdate,content,operation </sql> <insert id="insert" parameterType="com.hz.yiliao.orm.Log" useGeneratedKeys="true" keyProperty="id" keyColumn="id"> insert into t_log(<include refid="LogSQL"/>) value(#{userId},NOW(),#{content},#{operation}) </insert> </mapper>
日志记录Service层:
package com.hz.yiliao.bo; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.hz.yiliao.dao.LogMapper; import com.hz.yiliao.orm.AdminUser; import com.hz.yiliao.orm.Log; /** * 系统日志逻辑层 * @author Administrator * */ @Service public class LogBO { @Autowired private LogMapper logMapper; /** * 新增 * @param log */ @Transactional("transactionManager") public void insertLog(Log log){ logMapper.insert(log); } }
在MyBatis配置文件mybatis-config.xml中配置POJO,根据自己的要求配置,如果不知道怎么配置,看一下spring+mybatis整合
创建utils包,在utils包下创建切面类LogAspect:
package com.hz.yiliao.utils; import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import com.hz.yiliao.bo.LogBO; import com.hz.yiliao.orm.Log; /** * 系统日志AOP * @author Administrator * */ @Aspect public class LogAspect { @Autowired private LogBO logBO; /** * 添加业务逻辑方法切入点 */ @Pointcut("execution(* com.hz.yiliao.bo.*.insert(..))") public void insertCell(){} /** * 修改业务逻辑方法切入点 */ @Pointcut("execution(* com.hz.yiliao.bo.*.update(..))") public void updateCell(){} /** * 删除业务逻辑方法切入点 */ @Pointcut("execution(* com.hz.yiliao.bo.*.delete(..))") public void deleteCell(){} /** * 添加操作日志(后置通知) * @param joinPoint * @param rtv */ @SuppressWarnings("unused") @AfterReturning(value="insertCell()",argNames="rtv", returning="rtv") public void insertLog(JoinPoint joinPoint, Object rtv) throws Throwable{ Long userId = 1L; if(userId == null){//没有管理员登录 return ; } //判断参数 if(joinPoint.getArgs() == null){//没有参数 return ; } //获取方法名 String methodName = joinPoint.getSignature().getName(); //获取操作内容 String opContent = optionContent(joinPoint.getArgs(),methodName); Log log = new Log(); log.setUserId(userId); log.setContent(opContent); log.setOperation("添加"); logBO.insertLog(log); } /** * 管理员修改操作日志(后置通知) * @param joinPoint * @param rtv * @throws Throwable */ @SuppressWarnings("unused") @AfterReturning(value="updateCell()", argNames="rtv", returning="rtv") public void updateLog(JoinPoint joinPoint, Object rtv) throws Throwable{ Long userId = 1L; if(userId == null){//没有登录 return; } //判断参数 if(joinPoint.getArgs() == null){//没有参数 return; } //获取方法名 String methodName = joinPoint.getSignature().getName(); //获取操作内容 String opContent = optionContent(joinPoint.getArgs(), methodName); //创建日志对象 Log log = new Log(); log.setUserId(userId); log.setContent(opContent); log.setOperation("修改");//操作 logBO.insertLog(log); } /** * 删除操作 * @param joinPoint * @param rtv */ @SuppressWarnings("unused") @AfterReturning(value="deleteCell()",argNames="rtv", returning="rtv") public void deleteLog(JoinPoint joinPoint, Object rtv) throws Throwable{ Long userId = 1L; if(userId == null){//没有登录 return; } //判断参数 if(joinPoint.getArgs() == null){//没有参数 return; } //获取方法名 String methodName = joinPoint.getSignature().getName(); StringBuffer rs = new StringBuffer(); rs.append(methodName); String className = null; for(Object info : joinPoint.getArgs()){ //获取对象类型 className = info.getClass().getName(); className = className.substring(className.lastIndexOf(".") + 1); rs.append("[参数1,类型:" + className + ",值:(id:" + joinPoint.getArgs()[0]+")"); } //创建日志对象 Log log = new Log(); log.setUserId(userId); log.setContent(rs.toString()); log.setOperation("删除");//操作 logBO.insertLog(log); } /** * 使用Java反射来获取被拦截方法(insert、update)的参数值, * 将参数值拼接为操作内容 * @param args * @param mName * @return */ public String optionContent(Object[] args, String mName){ if(args == null){ return null; } StringBuffer rs = new StringBuffer(); rs.append(mName); String className = null; int index = 1; //遍历参数对象 for(Object info : args){ //获取对象类型 className = info.getClass().getName(); className = className.substring(className.lastIndexOf(".") + 1); rs.append("[参数"+index+",类型:" + className + ",值:"); //获取对象的所有方法 Method[] methods = info.getClass().getDeclaredMethods(); // 遍历方法,判断get方法 for(Method method : methods){ String methodName = method.getName(); // 判断是不是get方法 if(methodName.indexOf("get") == -1){//不是get方法 continue;//不处理 } Object rsValue = null; try{ // 调用get方法,获取返回值 rsValue = method.invoke(info); }catch (Exception e) { continue; } //将值加入内容中 rs.append("(" + methodName+ ":" + rsValue + ")"); } rs.append("]"); index ++; } return rs.toString(); } }
在applicationContext.xml中加入新的配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-tx-3.0.xsd"> <!-- 加入Aspectj配置 --> <aop:aspectj-autoproxy /> <bean id="logAspect" class="com.hz.yiliao.utils.LogAspect" /> <context:component-scan base-package="com.hz.yiliao.bo,com.hz.yiliao.orm" /> <bean id="yiliaoDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/yiliao?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull" /> <property name="username" value="root" /> <property name="password" value="root" /> <property name="defaultAutoCommit" value="false" /> <property name="timeBetweenEvictionRunsMillis" value="3600000" /> <property name="minEvictableIdleTimeMillis" value="3600000" /> </bean> <bean id="yiliaoSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="yiliaoDataSource" /> <property name="typeAliasesPackage" value="com.hz.yiliao.orm" /> </bean> <bean id="mailSender" class="com.hz.yiliao.utils.MailSender"> <property name="javaMailSender" ref="javaMailSender" /> </bean> <bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host" value="smtp.163.com" /> <property name="username" value="yiliao_2014@163.com" /> <property name="password" value="yiliao2014" /> <property name="defaultEncoding" value="UTF-8" /> </bean> <import resource="mybatis-config.xml" /> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref local="yiliaoDataSource" /> </property> </bean> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**" /> <bean class="com.hz.yiliao.filt.YiliaoSysInterceptor" /> </mvc:interceptor> </mvc:interceptors> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> </beans>
配置成功后分别进行登录、添加、修改、删除等操作,日志记录表的内容如下:
相关推荐
4、想看spring aop 注解实现记录系统日志并入库等 二、能学到什么 1、收获可用源码 2、能够清楚的知道如何用spring aop实现自定义注解以及注解的逻辑实现 (需要知道原理的请看spring aop源码,此处不做赘述) 3、...
在Java开发中,Spring AOP(面向切面编程)是一个强大的功能,用于实现日志记录。AOP允许我们在不修改原有代码的情况下,插入新的行为,比如日志记录,事务管理等。下面将详细介绍如何在Spring框架中使用AOP来实现...
1. **切面(Aspect)**:切面是关注点的模块化,比如日志记录、事务管理、性能监控等。在Spring AOP中,切面由通知(Advice)和切点(Pointcut)定义。 2. **通知(Advice)**:通知是在特定连接点(Join Point)...
标题"spring aop实现日志功能"涉及到的是如何利用Spring AOP来记录和跟踪应用程序中的操作,这对于调试、性能分析和故障排查至关重要。下面我们将详细探讨如何通过Spring AOP来实现日志功能。 首先,理解AOP的基本...
在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许我们在不修改源代码的情况下,对程序进行横向关注点的插入,比如日志记录、事务管理、权限检查等。在这里,我们重点关注如何利用Spring AOP实现分层...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点问题,如日志、事务管理、安全性等。本示例将简要介绍如何在Spring应用中实现AOP,通过实际的...
另一方面,Spring AOP(面向切面编程)则是Spring框架的一个核心特性,用于实现跨切面的关注点,如日志记录。本篇文章将深入探讨如何将Swagger与Spring AOP结合起来,以实现优雅的日志记录功能。 首先,让我们了解...
总结来说,Spring AOP的日志管理是一个强大的工具,它帮助我们在不干扰业务逻辑的情况下实现日志记录。在MyEclipse中配置Spring库,结合JUnit4进行测试,可以有效地实现和验证这一功能。通过定义切面和通知,我们...
总结一下,Spring AOP提供了一种优雅的方式来处理系统的横切关注点,如日志记录、事务管理或性能监控。通过定义切点、创建切面和配置通知,我们可以实现代码的解耦,提高可维护性和复用性。这个例子提供了学习Spring...
综上所述,Spring.NET结合三层架构的AOP异常日志记录功能,为.NET开发者提供了一种有效管理异常和提高系统稳定性的解决方案。通过理解和实践,我们可以将这种技术应用到更广泛的项目中,提升系统的可维护性和可靠性...
spring aop实现接口参数变更前后对比和日志记录完整代码,拿到项目代码,只需要做数据库连接的修改即可运行起来使用,代码案例详细,真是可靠,代码原文地址:...
- **日志记录**:在方法调用前后记录操作信息。 - **事务管理**:自动进行事务的开启、提交、回滚等操作。 - **权限控制**:在访问敏感资源前进行权限检查。 - **性能监控**:记录方法执行时间,分析系统性能瓶颈。 ...
它通过非侵入性和轻量级的设计理念,使得开发者能够轻松地将诸如日志记录、事务管理等功能添加到现有的系统中,从而提高了代码的可维护性和扩展性。对于希望深入了解Spring AOP原理与实践的读者来说,掌握以上概念将...
结合logback和切面对参数名和参数值,方法运行时间,方法返回值记录日志,pom中需要添加ogback和切面依赖。
本节将详细介绍如何使用Spring AOP实现流程日志跟踪,主要关注于如何通过AOP拦截特定的类和方法来进行日志记录。 ##### 3.1 配置Spring AOP 在Spring配置文件中定义切面和切入点表达式是非常关键的一步。一般来说...
**Spring AOP在鉴权和日志记录中的应用** **一、引言** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的一个重要特性,它为开发者提供了在不修改源代码的情况下,对应用程序进行功能增强...
Spring AOP,全称为Aspect-Oriented Programming,是Spring框架中的一个重要组成部分,主要用来处理系统的横切关注点,如日志记录、事务管理、性能监控等。这些关注点通常会分散在应用程序的各个角落,而AOP就是为了...
通过以上方式,我们可以利用Spring AOP和元注解实现灵活的日志管理和分析,同时确保日志记录对系统性能的影响最小。这在大型Java应用中尤其重要,因为它提供了宝贵的运维数据,有助于问题排查和性能优化。
Spring AOP(面向切面编程)是...这样,我们可以保持业务逻辑的清晰,同时实现系统级的服务,如事务管理、日志记录、性能监控等。在实际项目中,正确配置和使用这些依赖库,对于实现高效、灵活的面向切面编程至关重要。