spring aop切面 记录日志功能

第一步:启用@AspectJ支持。

在你的工程lib目录下添加aspectjweaver.jar和aspectjrt.jar并在spring 的配置文件中添加如下代码:

  <aop:aspectj-autoproxy/>  // 这一步就完成了@AspectJ的支持,从而可以实现通过注解方式将通知编织到非公共方法中

 

第二步:编写自定义注解。实现对方法所实现的功能进行描述,以便在通知中获取描述信息,代码非常简单

package com.abchina.rmpf.logmng.ann;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface rmpfLog {
  String desc() default "无描述信息";
}

 

第三步:编写操作日志切面通知实现类。

在编写切面通知实现类之前,我们需要搞清楚我们需要哪些通知类型,是前置通知、后置通知、环绕通知或异常通知?根据我的需求,我们知道我们记录的操作日志有两种情况,一种是操作成功,一种是操作失败。操作成功时则方法肯定已经执行完成,顾我们需要实现一个后置通知;操作失败时则说明方法出现异常无法正常执行完成,顾还需要一个异常通知。因此我们就需要实现这两个通知即可。

@Aspect //该注解标示该类为切面类
public class LogAspect {

/**
* LogService
* @generated
*/
private ILogService logService;

//标注该方法体为后置通知,当目标方法执行成功后执行该方法体
@AfterReturning("within(com.abchina.irms..*) && @annotation(rl)")
public void addLogSuccess(JoinPoint jp, rmpfLog rl){
Object[] parames = jp.getArgs();//获取目标方法体参数
String params = parseParames(parames); //解析目标方法体的参数
String className = jp.getTarget().getClass().toString();//获取目标类名
className = className.substring(className.indexOf("com"));
String signature = jp.getSignature().toString();//获取目标方法签名
String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("("));
String modelName = getModelName(className); //根据类名获取所属的模块

String ip = (String)ActionContext.getContext().getSession().get(Constant.THREAD_APP_IP_KEY); //用户IP
ActorVO actor = ((ActorVO)ActionContext.getContext().getSession().get(Constant.SESSION_ACTOR_KEY));
LogVO logvo = new LogVO();
logvo.setId(java.util.UUID.randomUUID().toString());
logvo.setClassname(className);
logvo.setMethodname(methodName);
logvo.setArgument(params);
logvo.setMemo(rl.desc());
logvo.setModelname(modelName);
logvo.setIp(ip);
logvo.setOperationtime(DateTool.getDateTime4());
// logvo.setErr("");
logvo.setFlag("1");

if(actor!=null){
logvo.setOrgid(actor.getOrgcode());
logvo.setUserid(actor.getUserid());
logvo.setUsername(actor.getUsername());
}

logService.insertLog(logvo);
}

//标注该方法体为异常通知,当目标方法出现异常时,执行该方法体
@AfterThrowing(pointcut="within(com.abchina.irms..*) && @annotation(rl)", throwing="ex")
public void addLog(JoinPoint jp, rmpfLog rl, BusinessException ex){
Object[] parames = jp.getArgs();
String params = parseParames(parames);
String className = jp.getTarget().getClass().toString();
className = className.substring(className.indexOf("com"));
String signature = jp.getSignature().toString();
String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("("));
String modelName = getModelName(className);

String ip = (String)ActionContext.getContext().getSession().get(Constant.THREAD_APP_IP_KEY);
ActorVO actor = ((ActorVO)ActionContext.getContext().getSession().get(Constant.SESSION_ACTOR_KEY));
LogVO logvo = new LogVO();
logvo.setId(java.util.UUID.randomUUID().toString());
logvo.setClassname(className);
logvo.setMethodname(methodName);
logvo.setArgument(params);
logvo.setMemo(rl.desc());
logvo.setModelname(modelName);
logvo.setIp(ip);
logvo.setOperationtime(DateTool.getDateTime4());
logvo.setErr(ex.toString());//记录异常信息
logvo.setFlag("0");

if(actor!=null){
logvo.setOrgid(actor.getOrgcode());
logvo.setUserid(actor.getUserid());
logvo.setUsername(actor.getUsername());
}

logService.insertLog(logvo);
}

这两个方法体分别是后置通知和异常通知的实现。它们有两个相同的参数jp和rl,jp是切点对象,通过该对象可以获取切点所切入方法所在的类,方法名、参数等信息,具体方法可以看方法体的实现;rl则是我们的自定义注解的对象,通过该对象我们可以获取注解中参数值,从而获取方法的描述信息。在异常通知中多出了一个ex参数,该参数是方法执行时所抛出的异常,从而可以获取相应的异常信息。此处为我写的自定义异常。注意:如果指定异常参数,则异常对象必须与通知所切入的方法体抛出的异常保持一致,否则该通知不会执行。

 

第四步:在spring配置文件中创建通知bean对象。

 

<bean id="logAspect" class="com.abchina.rmpf.logmng.aop.LogAspect">
<property name="logService">
<ref local="com.abchina.rmpf.logmng.service.impl.LogServiceImpl"/>
</property>
</bean>

 

第五步:使用操作日志记录注解通过以上四步操作后,操作日志的记录功能就算完成了,那我们该如何使用呢?很简单!在com/abchina/irms目录下及其所有子目录下任意找到一个service层的某个类的方法,在其方法体上添加@rmpfLog(desc=”描述信息”)即可。代码如下:

@rmpfLog(desc="this is test")
@Transactional
public void insertRtcont(RtcontVO rtcontVO) throws BusinessException {
      rtcontAL.insertRtcont(toRtcontDomain(rtcontVO));
}

 

 

posted on 2014-11-17 18:43  264073578  阅读(518)  评论(0)    收藏  举报

导航