Spring AOP实现日志管理

释放双眼,带上耳机,听听看~!

在一些Web管理系统项目中,日志管理功能也常见,管理系统中日志主要是记录一些谁操作了什么东西,系统是否有异常等信息。那么如何在编程中实现呢?在Java面对对象语言中要实现日志管理功能时,是比较麻烦的。在此,引入了Spring框架中的AOP思想,AOP的主要作用是可以横向插入可重复代码(日志管理),在面向对象语言中是无法做到的,它是面向对象的一种延伸。而AspectJ是AOP的一个纯Java框架,而AspectJ实现AOP有两种方式(要添加相应jar包):一种是基于xml实现,另外一种是基于注解实现。实现日志管理是用基于注解来实现的,因为使用注解方式比较灵活。
在实现功能之前,首先要了解AOP相关的一些术语:
Aspect (切面):在实际应用中,切面通常是指封装的用于横向插入系统功能(如事务、日志等)的类。
Joinpoint (连接点):方法的调用。(调用要记录日志的方法)
Pointcut (切入点):通常是指类名、方法名或者方法上的注解(要记录日志的方法名或者方法上的注解)
Advice(通知/增强处理):可以将其理解为切面类中的方法,它是切面的具体实现(日志类实现方法)。
那么,该如何使用AspectJ基于注解来实现日志管理呢?
实现的大致思路是:
1.设计日志表和日志类,编写日志Dao和Service以及实现
2.自定义注解,注解中加入几个属性,属性可以标识操作的类型(方法是做什么的)
3.编写切面,切点表达式使用上面的注解直接定位到使用注解的方法,
4.编写通知,通过定位到方法,获取上面的注解以及注解的属性,然后从session中直接获取或者从数据库获取当前登录用户的信息,最后根据业务处理一些日志信息之后调用日志Service存储日志。

  1. 设计相关的日志表,编写相关的接口和接口实现类(Dao、Service)

Spring AOP实现日志管理

  1. 自定义日志注解


1
2
3
4
5
6
7
1@Retention(RetentionPolicy.RUNTIME)
2@Target(ElementType.METHOD)
3public @interface LogAnnotation {
4   String operateType();//记录日志操作类型
5}
6
7
  1. 编写切面类,注入service层的对象,配置切入点,该切入点是方法上的注解。日志管理使用的是@Around环绕通知,然后通过ProceedingJoinPoint对象来获取到方法(切入点),再通过该方法获取到方法上的注解,获取到注解里面的属性值(日志操作说明)。获取到用户信息,把相关值设置到Log对象中,然后执行ProceedingJoinPoint对象proceed()方法(连接点),然后包Log对象保存到数据库中。

注意:如果涉及到事务或者自定义异常类还需要在切面类try…catch…捕获异常中的catch抛出异常,给上一级调用者处理,要不然会把异常处理掉,不能抛出。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
1@Aspect
2@Component//声明一个bean
3public class LogAspect {
4   @Autowired
5   private LogService logService;//日志service
6   //切入点
7   @Pointcut("@annotation(com.koi.annotation.LogAnnotation)")
8   public void myPointcut(){}
9   //环绕通知 使用@LogAnnotation注解的方法
10  @Around("myPointcut()")
11  public Object aroundAdvice(ProceedingJoinPoint  pjp) throws Throwable{
12      Signature signature = pjp.getSignature();//获取方法签名
13      Method method = ( (MethodSignature)signature ).getMethod();//获取方法
14       //这个方法才是目标对象上有注解的方法
15      Method declaredMethod = pjp.getTarget().getClass().getDeclaredMethod(signature.getName(), method.getParameterTypes());
16      LogAnnotation annotation = declaredMethod.getAnnotation(LogAnnotation.class);//获取方法上的LogAnnotation注解
17      String operateType = annotation.operateType();//获取操作说明
18      //获取操作用户信息
19      Subject subject = SecurityUtils.getSubject();
20      UUser user = (UUser)subject.getPrincipal();
21      // 创建一个日志对象(准备记录日志)
22      Log log=new Log();
23      log.setOperateType(operateType);//操作说明
24      log.setOperateor(user.getNickname());//设置操作人
25      Object obj=null;
26      try {
27          obj=pjp.proceed();
28          log.setOperateResult("操作成功");//设置操作状态
29      } catch (CustomException e) {
30          log.setOperateResult("操作失败");//设置操作状态
31          throw e;//抛给自定义异常处理器处理
32      }finally{
33          log.setOperateDate(new Date());//设置当前时间
34          logService.addLog(log);
35      }
36      return obj;
37  }
38}
39
40

在需要记录日志的方法(一般是Service实现类的方法)上添加自定义的日志注解@LogAnnotation


1
2
3
4
5
6
7
8
1@LogAnnotation(operateType="修改密码")
2   @Override
3   public ResultInfo updatePassword(UUser user, String oldPassword)
4           throws Exception {
5       .....
6   }
7
8

最后,在spring.xml容器中(父容器)添加 <aop:aspectj-autoproxy /> 配置,启动对aspectj的支持。
如果日志操作(自定义日志注解)可以在controller控制层方法中执行,该<aop:aspectj-autoproxy />还要配置在spring-mvc.xml容器(子容器)中。因为spring.xml与spring-mvc.xml是父子容器关系,父容器不可以访问到子容器的对象,而子容器可以访问到父容器的对象,但只是针对对象来说,而<aop:aspectj-autoproxy />该配置不是对象,只是开启对aspectj的支持。如果把该配置单单放在父容器中,控制层(spring-mvc.xml子容器)就对aspectj的不支持了,所以应该在父子容器都配置<aop:aspectj-autoproxy />。

给TA打赏
共{{data.count}}人
人已打赏
安全技术

c++ list, vector, map, set 区别与用法比较

2022-1-11 12:36:11

安全经验

高并发大流量系统之限流技术

2021-11-28 16:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索