前言
使用AspectJ基于schema方式实现aop记录日志。spring版本为3.0。
一、第一种:xml实现过程
1. 建立Log对象,用于封装日志信息
import java.io.Serializable;
import org.springframework.util.StringUtils;
/**
* 日志对象
* @author
* @date 2015-1-14 下午04:51:02
*/
public class Log implements Serializable {
private static final long serialVersionUID = -5209175352207530987L;
/**
* 操作结果 success|failure
*/
private String operResult;
/**
* 操作名称
*/
private String operName;
/**
* 操作人(未使用)
*/
private String operator;
/**
* 操作参数
*/
private String operParams;
/**
* 操作开始时间
*/
private String operBeginTime;
/**
* 操作结束时间
*/
private String operEndTime;
/**
* 异常消息
*/
private String resultMsg;
public String getOperParams() {
return operParams;
}
public void setOperParams(String operParams) {
if(StringUtils.hasLength(this.operParams)){
this.operParams += "&&" + operParams;
}else{
this.operParams = operParams;
}
}
// 省略部分get、set方法
@Override
public String toString() {
return "Log [operResult=" + operResult + ", operName=" + operName
+ ", operator=" + operator + ", operParams=" + operParams
+ ", operBeginTime=" + operBeginTime + ", operEndTime="
+ operEndTime + ", resultMsg=" + resultMsg + "]";
}
}
/**
* AOP日志环绕增强
* @author
* @date 2015-1-14 下午04:50:22
*/
public class AspectLogger {
Logger logger = Logger.getLogger(this.getClass());
public void record(ProceedingJoinPoint pjp) {
logger.info("aop : begin call " + pjp.getTarget() + "."
+ pjp.getSignature().getName());
Log log = new Log();
try {
log.setOperName(pjp.getSignature().getName()); // 记录方法名
Object[] args = pjp.getArgs();
for (Object obj : args) {
log.setOperParams(obj.toString()); // 记录参数信息
}
log.setOperBeginTime(DateUtil.getCurrentTime());
Object result = pjp.proceed(); // 反射调用目标连接点方法,即调用原方法
log.setOperEndTime(DateUtil.getCurrentTime());
log.setOperResult("success");
return result; // 必须返回值,否则有返回值的方法不能正确对数据返回
} catch (Throwable e) {// 记录异常的详细信息
StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(stringWriter);
StringBuffer buffer = stringWriter.getBuffer();
e.printStackTrace(writer);
logger.error(buffer.toString());
log.setOperResult("failure");
log.setResultMsg(e.getMessage());
} finally {
logger.info("aop : " + log.toString());
logger.info("aop : end call " + pjp.getTarget() + "."
+ pjp.getSignature().getName());
}
}
}
3. sprinig中xml配置(applicationContext.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">
<!-- 配置日志记录器 -->
<bean id="logger" class="com.cmcc.sleepgw.aop.AspectLogger"></bean>
<!-- aop配置 -->
<aop:config proxy-target-class="true">
<!-- 日志切入点 -->
<aop:pointcut id="loggerPointcut" expression="(execution(* *..*Service.*(..))) or execution(* *..*Controller.*(..))" />
<aop:aspect id="loggerAspect" ref="logger">
<aop:around method="record" pointcut-ref="loggerPointcut" />
</aop:aspect>
</aop:config>
</beans>
注意事项与问题
1. 如果是SpringMVC框架,需要在spring的mvc配置文件中加入下面代码,否则aop不能生效
<aop:aspectj-autoproxy proxy-target-class="true"/>
可先尝试在applicationContext.xml中读取aop处理的service的bean对象,然后调用方法来确定aop是否生效。之前一直以为是横切规则写的有问题未使aop生效,后在配置文件中读取bean,测试aop生效,推测出是特定框架的问题。
proxy-target-class默认为false,表示JDK动态代理,true时为Cglib动态代理。如果代理类没有接口,即使配置为false也会使用Cglib代理。
二、第二种:注解方式简单实现
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ProjectAspect {
@Around("(execution(* *..*Service.*(..))) or execution(* *..*Controller.*(..))")
public void log(ProceedingJoinPoint pjp){
// 其他逻辑相同,略
}
}