Spring Aop 异步处理系统日志

摘要

往往一个系统的日志部分也是非常重要的,日志可以用来分析系统出现的异常信息,下面就分享一篇使用spring aop切面来异步添加日志的操作,其中用到了 队列和多线程。

 往往一个系统的日志部分也是非常重要的,日志可以用来分析系统出现的异常信息,下面就分享一篇使用spring aop切面来异步添加日志的操作,其中用到了 队列和多线程。

第一步:创建日志对象

import java.util.Date;  
  
import javax.persistence.Column;  
import javax.persistence.Entity;  
import javax.persistence.Id;  
import javax.persistence.Table;  
  
import org.hibernate.annotations.GenericGenerator;  
  
@Entity  
@Table(name="t_xt_audit_log")  
public class AuditLog  
{  
    @Id  
    @GenericGenerator(name = "paymentableGenerator", strategy = "assigned")     
    private String id;  
    private String description;  
    private String method;  
    private Integer type;  
    @Column(name="request_ip")  
    private String requestIp;  
    @Column(name="exception_code")  
    private String exceptionCode;  
    @Column(name="exception_detail")  
    private String exceptionDetail;  
    private String params;  
    @Column(name="create_by")  
    private String createBy;  
    @Column(name="create_date")  
    private Date createDate;  
    @Column(name="app_id")  
    private String appId;  
    public String getId()  
    {  
        return id;  
    }  
    public void setId(String id)  
    {  
        this.id = id;  
    }  
    public String getDescription()  
    {  
        return description;  
    }  
    public void setDescription(String description)  
    {  
        this.description = description;  
    }  
    public String getMethod()  
    {  
        return method;  
    }  
    public void setMethod(String method)  
    {  
        this.method = method;  
    }  
    public Integer getType()  
    {  
        return type;  
    }  
    public void setType(Integer type)  
    {  
        this.type = type;  
    }  
    public String getRequestIp()  
    {  
        return requestIp;  
    }  
    public void setRequestIp(String requestIp)  
    {  
        this.requestIp = requestIp;  
    }  
    public String getExceptionCode()  
    {  
        return exceptionCode;  
    }  
    public void setExceptionCode(String exceptionCode)  
    {  
        this.exceptionCode = exceptionCode;  
    }  
    public String getExceptionDetail()  
    {  
        return exceptionDetail;  
    }  
    public void setExceptionDetail(String exceptionDetail)  
    {  
        this.exceptionDetail = exceptionDetail;  
    }  
    public String getParams()  
    {  
        return params;  
    }  
    public void setParams(String params)  
    {  
        this.params = params;  
    }  
    public String getCreateBy()  
    {  
        return createBy;  
    }  
    public void setCreateBy(String createBy)  
    {  
        this.createBy = createBy;  
    }  
    public Date getCreateDate()  
    {  
        return createDate;  
    }  
    public void setCreateDate(Date createDate)  
    {  
        this.createDate = createDate;  
    }  
    public String getAppId()  
    {  
        return appId;  
    }  
    public void setAppId(String appId)  
    {  
        this.appId = appId;  
    }  
      
      
}


第二步:创建存放日志的队列

import java.util.concurrent.BlockingQueue;  
import java.util.concurrent.LinkedBlockingQueue;  
import java.util.concurrent.TimeUnit;  
  
import org.springframework.stereotype.Component;  
  
import com.izhbg.typz.sso.audit.dto.AuditLog;  
  
  
@Component  
public class AuditLogQueue {  
    private BlockingQueue<AuditLog> blockingQueue = new LinkedBlockingQueue<AuditLog>();  
  
    public void add(AuditLog auditLog) {  
        blockingQueue.add(auditLog);  
    }  
  
    public AuditLog poll() throws InterruptedException {  
        return blockingQueue.poll(1, TimeUnit.SECONDS);  
    }  
}

第三步:保存日志的线程,从队列中读取日志

import java.util.ArrayList;  
import java.util.List;  
  
import javax.annotation.PostConstruct;  
import javax.annotation.PreDestroy;  
import javax.annotation.Resource;  
  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.springframework.stereotype.Component;  
  
import com.izhbg.typz.sso.audit.dto.AuditLog;  
import com.izhbg.typz.sso.audit.service.AuditLogService;  
  
/** 
 *  
* @ClassName: AuditLogConsumer  
* @Description: 日志的保存线程 
* @author caixl  
* @date 2016-5-11 上午11:23:12  
* 
 */  
@Component  
public class AuditLogConsumer  implements Runnable{  
  
    private static Logger logger = LoggerFactory.getLogger(AuditLogConsumer.class);  
    public static final int DEFAULT_BATCH_SIZE = 64;  
    private AuditLogQueue auditLogQueue;  
    private AuditLogService auditLogService;  
    private int batchSize = DEFAULT_BATCH_SIZE;  
    private boolean active = true;  
    private Thread thread;  
      
    @PostConstruct  
    public void init() {  
        thread = new Thread(this);  
        thread.start();  
    }  
  
    @PreDestroy  
    public void close() {  
        active = false;  
    }  
  
    public void run() {  
        while (active) {  
            execute();  
        }  
    }  
      
    public void execute() {  
        List<AuditLog> auditDtos = new ArrayList<AuditLog>();  
  
        try {  
            int size = 0;  
  
            while (size < batchSize) {  
                AuditLog auditLog = auditLogQueue.poll();  
  
                if (auditLog == null) {  
                    break;  
                }  
  
                auditDtos.add(auditLog);  
                size++;  
            }  
        } catch (Exception ex) {  
            logger.info(ex.getMessage(), ex);  
        }  
  
        if (!auditDtos.isEmpty()) {  
         auditLogService.batchLog(auditDtos);//持久化日志到数据库
        }
    }
    @Resource  
    public void setAuditLogQueue(AuditLogQueue auditLogQueue) {  
        this.auditLogQueue = auditLogQueue;  
    }  
    @Resource  
    public void setAuditLogService(AuditLogService auditLogService) {  
        this.auditLogService = auditLogService;  
    }  
  
    public void setBatchSize(int batchSize) {  
        this.batchSize = batchSize;  
    }  
}

第四步:创建 controller层 自定义注解

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;  
  
  
/** 
 *      
* @ClassName: SystemControllerLog  
* @Description: 自定义注解 拦截Controller   
* @author caixl  
* @date 2016-5-10 下午2:16:12  
* 
 */  
@Target({ElementType.PARAMETER, ElementType.METHOD})      
@Retention(RetentionPolicy.RUNTIME)      
@Documented      
public  @interface SystemControllerLog {      
    String description()  default "";      
}

第五步:创建service层自定义注解

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;  
/** 
 *  
* @ClassName: SystemServiceLog  
* @Description: 自定义注解 拦截service   
* @author caixl  
* @date 2016-5-10 下午2:17:12  
* 
 */  
@Target({ElementType.PARAMETER, ElementType.METHOD})      
@Retention(RetentionPolicy.RUNTIME)      
@Documented      
public  @interface SystemServiceLog {      
    String description()  default "";      
}

第六步:创建切点

import java.lang.reflect.Method;  
import java.util.Date;  
  
import javax.annotation.Resource;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpSession;  
  
import net.sf.json.util.JSONUtils;  
  
import org.apache.log4j.Logger;  
import org.aspectj.lang.JoinPoint;  
import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.annotation.Before;  
import org.aspectj.lang.annotation.Pointcut;  
import org.springframework.stereotype.Component;  
import org.springframework.web.context.request.RequestContextHolder;  
import org.springframework.web.context.request.ServletRequestAttributes;  
  
import com.izhbg.typz.base.util.CommonUtil;  
import com.izhbg.typz.base.util.IdGenerator;  
import com.izhbg.typz.sso.audit.component.AuditLogQueue;  
import com.izhbg.typz.sso.audit.dto.AuditLog;  
import com.izhbg.typz.sso.audit.manager.AuditLogManager;  
import com.izhbg.typz.sso.util.SpringSecurityUtils;  
/** 
 *  
* @ClassName: AuditLogAspect  
* @Description: 切点类 
* @author caixl  
* @date 2016-5-10 下午2:50:34  
* 
 */  
@Aspect      
@Component  
public class AuditLogAspect  
{  
     private  AuditLogQueue auditLogQueue;  
    //本地异常日志记录对象      
     private  static  final Logger logger = Logger.getLogger(AuditLogManager.class);   
       
     //Service层切点      
     @Pointcut("@annotation(com.izhbg.typz.sso.annotation.SystemServiceLog)")      
     public  void serviceAspect() {      
     }  
     //Controller层切点      
     @Pointcut("@annotation(com.izhbg.typz.sso.annotation.SystemControllerLog)")      
     public  void controllerAspect() {      
     }   
       
     @Before("controllerAspect()")      
     public  void doBefore(JoinPoint joinPoint) { //@ TODO 异步线程处理   
         HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();  
         HttpSession session = request.getSession();      
         //读取session中的用户      
         //请求的IP      
         String ip = CommonUtil.getIpAddress(request);  
        //获取用户请求方法的参数并序列化为JSON格式字符串      
         String params = "";      
          if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {      
              for ( int i = 0; i < joinPoint.getArgs().length; i++) {      
                 params += JSONUtils.valueToString(joinPoint.getArgs()[i]) + ";";      
             }      
         }  
         try {      
            //*========控制台输出=========*//      
            System.out.println("=====前置通知开始=====");      
            System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));      
            System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));      
            System.out.println("请求人:" + SpringSecurityUtils.getCurrentUsername());      
            System.out.println("请求IP:" + ip);      
            //*========数据库日志=========*//      
            AuditLog log = new AuditLog();  
            log.setId(IdGenerator.getInstance().getUniqTime()+"");  
            log.setDescription(getControllerMethodDescription(joinPoint));      
            log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));      
            log.setType(0);      
            log.setRequestIp(ip);      
            log.setExceptionCode( null);      
            log.setExceptionDetail( null);      
            log.setParams( params);      
            log.setCreateBy(SpringSecurityUtils.getCurrentUsername()+"("+SpringSecurityUtils.getCurrentUserId()+")");      
            log.setCreateDate(new Date());      
            log.setAppId(SpringSecurityUtils.getCurrentUserAppId());  
            //保存数据库      
            auditLogQueue.add(log);     
            System.out.println("=====前置通知结束=====");      
        }  catch (Exception e) {      
            //记录本地异常日志      
            logger.error("==前置通知异常==");      
        }      
     }  
       
       
    /** 
     * 获取注解中对方法的描述信息 用于service层注解 
     *  
     * @param joinPoint 
     *            切点 
     * @return 方法描述 
     * @throws Exception 
     */  
    public static String getServiceMthodDescription(JoinPoint joinPoint) throws Exception  
    {  
        String targetName = joinPoint.getTarget().getClass().getName();  
        String methodName = joinPoint.getSignature().getName();  
        Object[] arguments = joinPoint.getArgs();  
        Class targetClass = Class.forName(targetName);  
        Method[] methods = targetClass.getMethods();  
        String description = "";  
        for (Method method : methods)  
        {  
            if (method.getName().equals(methodName))  
            {  
                Class[] clazzs = method.getParameterTypes();  
                if (clazzs.length == arguments.length)  
                {  
                    description = method.getAnnotation(SystemServiceLog.class).description();  
                    break;  
                }  
            }  
        }  
        return description;  
    }  
  
    /** 
     * 获取注解中对方法的描述信息 用于Controller层注解 
     *  
     * @param joinPoint 
     *            切点 
     * @return 方法描述 
     * @throws Exception 
     */  
    public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception  
    {  
        String targetName = joinPoint.getTarget().getClass().getName();  
        String methodName = joinPoint.getSignature().getName();  
        Object[] arguments = joinPoint.getArgs();  
        Class targetClass = Class.forName(targetName);  
        Method[] methods = targetClass.getMethods();  
        String description = "";  
        for (Method method : methods)  
        {  
            if (method.getName().equals(methodName))  
            {  
                Class[] clazzs = method.getParameterTypes();  
                if (clazzs.length == arguments.length)  
                {  
                    description = method.getAnnotation(SystemControllerLog.class).description();  
                    break;  
                }  
            }  
        }  
        return description;  
    }  
    @Resource  
    public void setAuditLogQueue(AuditLogQueue auditLogQueue) {  
        this.auditLogQueue = auditLogQueue;  
    }  
      
      
      
      
  
}

使用方式:

@RedisCache(type=TXtYh.class,fieldKey="parameterMap.yhId")  
    @RequestMapping("user-edit")  
    @SystemControllerLog(description = "编辑用户")  
    public String userEdit(@RequestParam Map<String, Object> parameterMap, Model model) throws Exception{  
          
        String yhId= StringUtils.getString(parameterMap.get("yhId"));  
        String currentAppId= StringUtils.getString(parameterMap.get("currentAppId"));  
        TXtYh user = null;  
        if(StringHelper.isNotEmpty(yhId))  
            user = tXtYhService.findByYhId(yhId);  
        String result = tXtJgService.getJgsJSON(currentAppId);  
        model.addAttribute("user", user);  
        model.addAttribute("result", result);  
        model.addAttribute("currentAppId", currentAppId);  
          
        List<TXtYy> tXtYyList = tXtYyService.queryAll();  
        model.addAttribute("txtYy", tXtYyList);  
        return "admin/guser/getguser";  
    }


IT家园
IT家园

网友最新评论 (0)