Spring AOP面向切面编程,主要用于日志记录、性能监控、安全检测等
相关术语:
1.切面(Aspect) 适用于类中(@Aspect)
2.连接点(JoinPoint) 一个连接点代表一个方法的执行
3.通知(Advice) 包括 around、before、after 等通知类型,一般都是用拦截器做通知模型(拦截器链)
4.切入点(Pointcut)定义出一个或一组方法,当执行这些方法时可产生通知,Spring缺省使用AspectJ切入点语法
通知类型
· 前置通知(@Before):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)
· 返回后通知(@AfterReturning):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回
· 抛出异常后通知(@AfterThrowing):方法抛出异常退出时执行的通知
· 后通知(@After):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)
· 环绕通知(@Around):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型,环绕通知可以在方法调用前后完成自定义的行为,它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行
Spring Aop配置的两种方式:
1.Xml
2.注解
今天介绍记录日志怎么通过AOP实现
1.自定义系统日志注解
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)
public @interface LogAnnotation {
String value();
}
2.AOP解析类
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.my.data.cache.annotation.LogAnnotation;
import com.my.data.cache.consit.SystemConsist;
import com.my.data.cache.domain.Log;
import com.my.data.cache.service.LogService;
import com.my.data.cache.utils.ExceptionUtil;
import com.my.data.cache.utils.SpringWebUtil;
/**
*
* 拦截所有的service方法,系统全局应用日志记录
*/
@Component
@Aspect
public class GlobalLoggerAdvisor {
private static final String LOG_RESULT_SUCCESS = "操作成功";
private static final String LOG_RESULT_ERROR = "操作失败";
@Autowired
private LogService logService;
@Pointcut("execution(* com.my.data.cache.service.*Service.*(..))")
private void aspectjMethod(){};
@Around(value = "aspectjMethod()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
//调用核心逻辑
Object retVal = pjp.proceed();
成功日志记录
MethodSignature signature = (MethodSignature) pjp.getSignature();
LogAnnotation logAnnotation = signature.getMethod().getAnnotation(LogAnnotation.class);
if(logAnnotation != null){
String ip = "";
String operator = "";
if(SpringWebUtil.getRequest() != null){
ip = getRemoteAddress(SpringWebUtil.getRequest());
if("0:0:0:0:0:0:0:1".equals(ip)){
ip = "localhost";
}
if(SpringWebUtil.getRequest().getSession().getAttribute(SystemConsist.CURRENT_USER) != null){
operator = SpringWebUtil.getRequest().getSession().getAttribute(SystemConsist.CURRENT_USER).toString();
}
}
saveLogInfo(ip,
LOG_RESULT_SUCCESS, logAnnotation.value(), operator);
}
return retVal;
}
@AfterThrowing(value = "aspectjMethod()", throwing = "ex")
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
LogAnnotation logAnnotation = signature.getMethod().getAnnotation(LogAnnotation.class);
if(logAnnotation != null){
//异常日志记录
String ip = "";
String operator = "";
if(SpringWebUtil.getRequest() != null){
ip = getRemoteAddress(SpringWebUtil.getRequest());
if("0:0:0:0:0:0:0:1".equals(ip)){
ip = "localhost";
}
if(SpringWebUtil.getRequest().getSession().getAttribute(SystemConsist.CURRENT_USER) != null){
operator = SpringWebUtil.getRequest().getSession().getAttribute(SystemConsist.CURRENT_USER).toString();
}
}
saveLogInfo(ip,
LOG_RESULT_ERROR, ExceptionUtil.createStackTrackMessage(ex), operator);
}
}
private void saveLogInfo(String host, String result, String desc, String operator) {
Log log = new Log();
log.setIp(host);
log.setLogDesc(desc);
log.setOperator(operator);
log.setOperateDate(new Date());
log.setResult(result);
logService.saveLog(log);
System.out.println("记录日志成功");
}
private String getRemoteAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
ip = request.getRemoteAddr();
}
return ip;
}
}
3.日志服务接口
import com.my.data.cache.domain.Log;
public interface LogService {
public void saveLog(Log log);
public void logLoginInfo(String userName, String result);
}
4.日志业务实体类
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* 日志信息
*
*/
@Entity
@Table(name = "sys_log")
public class Log implements Serializable{
private static final long serialVersionUID = 2346530761836619342L;
@Id
private String id;
// 日志描述
private String logDesc;
// 操作人
private String operator;
// 操作时间
private Date operateDate;
// 操作结果
private String result;
// IP地址
private String ip;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getLogDesc() {
return logDesc;
}
public void setLogDesc(String logDesc) {
this.logDesc = logDesc;
}
public String getOperator() {
return operator;
}
public void setOperator(String operator) {
this.operator = operator;
}
public Date getOperateDate() {
return operateDate;
}
public void setOperateDate(Date operateDate) {
this.operateDate = operateDate;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}