使用SpringAop与自定义注解实现日志记录
背景:使用spring有蛮久了,一直都觉得spring的优点是,通过spring容器替我们管理bean,降低程序的耦合性,也就是IOC,但是spring还有另一个优点,那就AOP,Aop叫做面向切面编程,最开始很是纠结,学习面向对象编程思维之后,竟然又冒出来一个面向切面,一直没没怎么关注,直到项目中后来使用了spring的日志记录功能之后,才大概的体会了面向切面的思想,这里简单记录一下,使用springAop记录用户操作日志过程,作为学习笔记。
简单回顾一下aop:
AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。
一 AOP的基本概念
(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知
(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类
二 Spring AOP
Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。
ok,就到这里,我这里不主要介绍使用aop,主要是记录一下自己使用aop的一个过程,并没有使用到aop的全部功能,只是实现了我自己想要的效果,达到目的就好了,接下来贴代码。
1.首先pom依赖包(可根据你项目自选版本也可直接到maven仓库搜索)
[code] <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.12</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.12</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency>
2.使用aop需要的配置文件
[code] <!-- 事务 aop 配置 --> <aop:config> <aop:pointcut id="serviceMethods" expression="execution(* cn.hejd.web.service..*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/> </aop:config> <!-- 配置使Spring采用CGLIB代理 --> <aop:aspectj-autoproxy proxy-target-class="true"/> <!-- 启用对事务注解的支持 --> <tx:annotation-driven transaction-manager="transactionManager"/>
3.自定义一个注解
[code]import java.lang.annotation.*; /** * @author HeJD * @date 2018/8/7 12:39 * @Description:自定义日志注解 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @Documented public @interface BussAnnotation { //模块名 String moduleName() default ""; //操作内容 String option() default ""; }
关于自定义注解及介绍参考:https://www.geek-share.com/detail/2626858704.html
4.声明一个切面类
[code] import org.apache.log4j.Logger; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * @Auther: HeJD * @Date: 2018/8/4 17:46 * @Description:日志切面类 */ @Component @Aspect public class LogInterceptor { private Logger logger =Logger.getLogger(LogInterceptor.class); @Autowired private LogService LogService; @Pointcut("execution(public * cn.hejd.web.serviceimpl..*.*(..))") public void serviceLogAspect() { } @Around(value = "serviceLogAspect() && @annotation(annotation) &&args(..) ", argNames = "pj,annotation") public ServerResponse interceptorApplogic(ProceedingJoinPoint pj, BussAnnotation annotation){ logger.info("=====================切面日志启动=========================="); LogService.printConsoleLog(pj,annotation); //输出日志到控制台 ServerResponse serverResponse=null; try { serverResponse=(ServerResponse)pj.proceed(); if (serverResponse.getStatus()!=0){ logger.info("当前用户执行结果:执行失败"); }else{ logger.info("当前用户执行结果:执行成功"); } }catch (Throwable e){ logger.info("当前用户执行结果:执行出现异常"); } logger.info("=====================切面日志结束=========================="); return serverResponse; } }
这里解释一下其中出现的类:
一:ServerResponse 是我自定义的服务器返回接口,因为我需要切面得到我执行方法后的放回值,所以我的切面返回值也是ServerResponse
二:LogService:日志的服务类,主要实现打印切面日志到控制台,以及可存储日志内容到数据库
切面切点表达式规则参考:https://www.geek-share.com/detail/2675794448.html
5.这里是LogService及其实现类,一块贴上来
[code]/** * @Auther: HeJD * @Date: 2018/8/6 09:43 * @Description:日志服务 */ public interface LogService { /** * @author HeJD * @date 2018/8/6 9:47 * @param [pj, annotation] * @return void * @Description:打印日志到控制台显示 */ void printConsoleLog(ProceedingJoinPoint pj, BussAnnotation annotation); //如果需要将添加到数据库,可在此添加 }
[code]/** * @Auther: HeJD * @Date: 2018/8/6 09:44 * @Description:日志服务 */ @Service("logService") public class LogServiceImpl implements LogService { private Logger logger=Logger.getLogger(LogServiceImpl .class); @Override public void printConsoleLog(ProceedingJoinPoint pj, BussAnnotation annotation) { //获取当前执行用户 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); Person Person = (Person) request.getSession().getAttribute(Const.CURRENT_USER); //获取当前执行操作的用户对象 logger.info("当前用户:"+Person.getName()); logger.info("当前用户执行模块:" + annotation.moduleName()); logger.info("当前用户执行操作:" + annotation.option()); //获取方法名 logger.info("当前用户执行方法:"+pj.getSignature().getName()); Method method=((MethodSignature)pj.getSignature()).getMethod(); logger.info("当前方法的放回类型"+method.getReturnType()); //获取系统时间 String time = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date()); logger.info("当前用户操作时间:"+time); for(Object obj : pj.getArgs()){ logger.info("当前用户执行的方法名参数:"+obj.toString()); } } }
接下来如何使用我们的自定义注解及切面的效果展示
[code] @BussAnnotation(moduleName = "商城管理",option = "更新-商家") @Override public ServerResponse updateFactory(Factory factory) { int result= FactoryMapper.updateByPrimaryKeySelective(factory); if (result>0){ return ServerResponse.createBySuccessMessage("编辑更新成功"); } return ServerResponse.createByErrorMessage("编辑更新失败"); }
直接在需要的方法上面添加我们自定义的注解,然后当这个方法被执行时就会记录日志,记录日志如下
我这里没有存入数据库,如果需要存入数据库,可以建一个表,再定义一个实体类,打印日志接收之后,将日志实体类对应存储日志的相关记录,再通过LogService即可添加到数据库,效果图如下,下图是从其它博客拿过来的,做演示使用:
阅读更多
- 使用自定义注解+Spring AOP 实现日志记录
- Spring+SpringMVC+Mybatis 利用AOP自定义注解实现可配置日志快照记录
- Spring+SpringMVC+Mybatis 利用AOP自定义注解实现可配置日志快照记录
- Spring AOP自定义注解实现系统日志记录管理
- Spring+SpringMVC+Mybatis 利用AOP自定义注解实现可配置日志快照记录
- spring aop自定义注解实现日志记录
- springboot 自定义注解+AOP 实现日志记录
- 自定义注解和aop结合使用---自定义日志记录的实现
- Spring AOP实现复杂的日志记录(自定义注解)
- SpringBoot使用自定义注解+拦截器 实现日志记录
- springboot aop 自定义注解方式实现一套完善的日志记录(完整源码)
- 使用Spring AOP和自定义注解记录日志
- springAOP自定义注解方式实现日志管理
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- Spring AOP 自定义注解记录操作日志
- spring2.x使用aop实现声明式日志记录
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- spring AOP自定义注解方式实现日志管理
- Spring Aop自定义注解实现日志管理