Spring:Aop记录日志
本博客默认读者已经了解Aop原理,有spring基础,不在此详细描述。
AOP简介
AOP(Aspect Oriented Programming),即面向切面编程。 (OOP:Object 面向对象编程)
有了AOP,你写代码时不需要把这个验证用户步骤写进去,即完全不考虑验证用户。只写取款和显示余额的业务代码。而在另一个地方,写好验证用户的代码。这个验证用户的代码就是切面代码,以后在执行取款和显示余额的时候,利用代理模式。将验证用户的功能在执行取款和显示余额前调用。
代码在Spring容器中执行的时候,通过配置告诉Spring你要把这段代码加到哪几个地方,Spring就会在执行正常业务流程的时候帮你把验证代码和取款代码织入到一起。
AOP真正目的是:你写代码的时候,只需考虑主流程,而不用考虑那些不重要的,但又必须要写的其它相同的代码,这些其它的相同代码所在的类就是切面类。
关键词解释
Aspect(切面):切面指的是切入点(规则)和通知(织入方法)的类=切入点+通知。
Pointcut(切入点):切入点指的是类或方法名,满足某一个规则的类或方法都是切入点,通过切入点表达式来指定规则。
Advice(通知):切入点处所要执行的程序代码,即切面类中要执行的公共方法。通知的类型有:前置通知,后置通知,异常通知,最终通知,环绕通知。
以黑马项目二为例
步骤
- 编写SpringMVC.xml,开启Aop自动代理
- 编写日志切面类(@Aspect),在切面类中需要保存日志
- 测试Aop,自动记录日志
实现
Aop(面向切面编程)是spring框架的一个特点,在实现Aop功能的时候需要在springmvc.xml文件中开启aop的注解扫描。
1. 编写springmvc.xml,开启Aop自动代理
<!--开启aop的注解扫描 自动扫描@Aspect、@pointCut、@Around这些注解-->
<aop:aspectj-autoproxy/>
2. 编写日志切面类
注解说明:
- 类上的注解
@Component
@Aspect
public class LogAspect {
在切面类的类名上加上@Component,表示将该类注册到spring容器中
在切面类的类名上加上@Aspect,通过此注解标识为切面类
- 方法上的注解
@Around(“execution(* com.cheung.web.controller...(…)) &&! execution( com.cheung.web.controller.system.SysLogController.*(…))”)
@Around表示将该方法标记为环绕通知,其中参数为切入点表达式(切入点表达式是可以使用逻辑运算符)
- 切入点表达式
切入点表达式由以下部分组成:
访问修饰符 返回类型 包名.类名.方法名(参数类型) 抛出异常类型
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
其中必须要填的参数是:
返回类型、方法名、参数类型
在切入点表达式中可以使用逻辑运算符
execution(* com.cheung.web.controller...(…)) &&! execution( com.cheung.web.controller.system.SysLogController.*(…))
本案例使用逻辑运算符将记录日志的controller排除在切面外,每次执行记录日志的时候就不会将“记录日志”这一没意义的日志保存到数据库。
环绕通知的要求:
public Object saveLog(ProceedingJoinPoint pj){方法体}
-
方法的返回值类型一定是Object,这里的返回值代表了目标方法的返回值
-
方法一定要有形参ProceedingJoinPoint ,ProceedingJoinPoint 代表的是目标方法
切面实现类代码:
package com.cheung.web.utils;
import com.cheung.domain.system.SysLog;
import com.cheung.domain.system.User;
import com.cheung.service.system.SysLogService;
import org.apache.shiro.web.session.HttpServletSession;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.UUID;
@Component
@Aspect
public class LogAspect {
@Autowired
private SysLogService sysLogService;
@Autowired
private HttpServletRequest request;
@Around("execution(* com.cheung.web.controller.*.*.*(..)) &&! execution(* com.cheung.web.controller.system.SysLogController.*(..))")
public Object saveLog(ProceedingJoinPoint pj){
try {
Object result = pj.proceed(); //放行目标方法
//执行完毕了方法,那么就应该记录日志
SysLog sysLog = new SysLog();
//设置id
sysLog.setId(UUID.randomUUID().toString());
//得到登陆者
User loginUser = (User) request.getSession().getAttribute("loginUser");
//设置操作人
sysLog.setUserName(loginUser.getUserName());
//设置ip
sysLog.setIp(request.getRemoteAddr());
//时间
sysLog.setTime(new Date());
//执行的目标方法名
sysLog.setMethod(pj.getSignature().getName());
//设置目标方法所属的类全名
sysLog.setAction(pj.getTarget().getClass().getName());//pj.getTarget()获取执行目标方法的对象
sysLog.setCompanyId(loginUser.getCompanyId());
sysLog.setUserName(loginUser.getCompanyName());
sysLogService.save(sysLog);
return result;
}catch (Throwable throwable){
throwable.printStackTrace();
throw new RuntimeException(throwable);
}
}
}
3.测试Aop记录日志效果
通过Aop技术实现了记录日志功能,当用户访问控制器方法时候日志表就会自动记录日志。
Memorial Day is 472 days |