项目开发中,有一个需求是这样的:登录用户在增删查改等操作时,需要记录用户每次操作的时间和操作的事件类型,用Spring的AOP编程就可以很容易实现这个需求。
AOP即面向切面的编程(Aspect Oriented Programming ),我们经常说面向切面的编程,但什么是面向切面?这里很多人有不同的理解,网上也有很多不同的答案,但很少有人能理解透彻并通过具体例子来讲解的。
一、配置AOP切面
<!-- 日志切面配置-->
<aop:config>
<aop:pointcut id="log" expression="execution(* com.xxx.service.*.*(..))" />
<aop:aspect ref="operatorAspect">
<aop:around method="recordOperator" pointcut-ref="log"/>
</aop:aspect>
</aop:config>
这个切面配置表明,系统中的所有service包中的类(甚至是子包中的类)所有方法,都可以通过operatorAspect类来进行做切面,这里的execution中的表达式可以上网查看具体的各种含义,operatorAspect类通过注解的方式声明。
@Aspect
@Component
public class OperatorAspect
{
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Operator {
public String operator();
}
这个注解可以理解为,凡是使用了这个注解的方法,都可以被代理,其中ElementType、RetentionPolicy等有多种取值,可以自己上网查找。
@Operator(operator="增加或更新文本消息")
public void saveTextMessage()
{
......
}
这里的operator=“增加或更新文本消息”,会被set到Operator注解的参数中。
四、切面类代理save方法
@After(value = "operator()")
public void recordOperator(ProceedingJoinPoint point) throws Throwable
{
Object[] param = point.getArgs(); // 方法参数列表
long begin = 0L; // 开始时间
long end = 0L;// 结束时间
begin = System.currentTimeMillis();
point.proceed();
end = System.currentTimeMillis();
// String operatorName = SpringSecurityUtil.getCurrentUserName();//操作人
String expend = (end - begin) + ""; // 一共花费多长时间
Signature signature = point.getSignature(); // 返回当前连接点签名
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
Operator operator = (Operator) Util.getAnnotation(method, Operator.class);
LogDaily logDaily = new LogDaily(); // 日志
logDaily.setCreateTime(new Date()); // 创建时间
logDaily.setExpendTime(expend); // 执行花费时间
logDaily.setOperatorName(userName); // 操作人
logDaily.setRecordType(""); // 操作类型
logDaily.setDescription(operator.operator());// 操作描述
logDailyService.insertLogDaily(logDaily);
}
这里的@After表明使用的是save方法之后的通知,point对象就把整个操作过程代理了,可以通过这个对象获得save方法的参数、注解的类容(即步骤三中的“增加或更新文本消息”)等信息。
如此一来,使用SpringAOP来做到日志记录的需求就完成了。