我是靠谱客的博主 眼睛大秀发,最近开发中收集的这篇文章主要介绍开启异步线程保存登录日志信息,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

  • 好处:开启异步线程,不会影响主线程中登录业务的运行。

  • 关键词:单例模式,异步管理器AsyncManager,异步工厂AsyncFactory,匿名内部类,线程
  • 使用AsyncManager开启异步线程,AsyncManager采用了单例模式进行实例化

    单例模式保证日志保存业务的单次执行,避免占用过多资源,异步线程影响到主线程

    
    /**
    * 异步任务管理器
    *
    *
    */
    public class AsyncManager{
    /**
    * 操作延迟10毫秒
    */
    private final int OPERATE_DELAY_TIME = 10;
    /**
    * 异步操作任务调度线程池
    */
    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
    /**
    * 单例模式
    */
    private AsyncManager(){}
    private static AsyncManager me = new AsyncManager();
    public static AsyncManager me(){
    return me;
    }
    /**
    * 执行任务
    *
    * @param task 任务
    */
    public void execute(TimerTask task){
    executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
    }
    /**
    * 停止任务线程池
    */
    public void shutdown(){
    Threads.shutdownAndAwaitTermination(executor);
    }
    }

  • 使用异步线程进行用户登录日志信息的保存

    //开启异步线程池
    AsyncManager.me().execute()
    //在异步线程中执行异步工厂中的任务
    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
  • 定义一个异步工厂AsyncFactory(用来编写需要异步运行的业务代码)

    
    /**
    * 异步工厂(产生任务用)
    *
    *
    */
    public class AsyncFactory {
    private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
    /**
    * 记录登录信息
    *
    * @param username 用户名
    * @param status
    状态
    * @param message
    消息
    * @param args
    列表
    * @return 任务task
    */
    public static TimerTask recordLogininfor(final String username, final String status, final String message,
    final Object... args) {
    final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
    final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
    return new TimerTask() {
    @Override
    public void run() {
    String address = AddressUtils.getRealAddressByIP(ip);
    StringBuilder s = new StringBuilder();
    s.append(LogUtils.getBlock(ip));
    s.append(address);
    s.append(LogUtils.getBlock(username));
    s.append(LogUtils.getBlock(status));
    s.append(LogUtils.getBlock(message));
    // 打印信息到日志
    sys_user_logger.info(s.toString(), args);
    // 获取客户端操作系统
    String os = userAgent.getOperatingSystem().getName();
    // 获取客户端浏览器
    String browser = userAgent.getBrowser().getName();
    // 封装对象
    SysLogininfor logininfor = new SysLogininfor();
    logininfor.setUserName(username);
    logininfor.setIpaddr(ip);
    logininfor.setLoginLocation(address);
    logininfor.setBrowser(browser);
    logininfor.setOs(os);
    logininfor.setMsg(message);
    // 日志状态
    if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status)) {
    logininfor.setStatus(Constants.SUCCESS);
    } else if (Constants.LOGIN_FAIL.equals(status)) {
    logininfor.setStatus(Constants.FAIL);
    }
    // 插入数据
    SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
    }
    };
    }
    /**
    * 操作日志记录
    *
    * @param operLog 操作日志信息
    * @return 任务task
    */
    public static TimerTask recordOper(final SysOperLog operLog) {
    return new TimerTask() {
    @Override
    public void run() {
    // 远程查询操作地点
    operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
    SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
    }
    };
    }
    }

  • 使用TimerTask实现Runnable接口的方法来创建线程

    public abstract class TimerTask implements Runnable {
    /**
    * This object is used to control access to the TimerTask internals.
    */
    final Object lock = new Object();
    /**
    * The state of this task, chosen from the constants below.
    */
    int state = VIRGIN;
    /**
    * This task has not yet been scheduled.
    */
    static final int VIRGIN = 0;
    /**
    * This task is scheduled for execution.
    If it is a non-repeating task,
    * it has not yet been executed.
    */
    static final int SCHEDULED
    = 1;
    /**
    * This non-repeating task has already executed (or is currently
    * executing) and has not been cancelled.
    */
    static final int EXECUTED
    = 2;
    /**
    * This task has been cancelled (with a call to TimerTask.cancel).
    */
    static final int CANCELLED
    = 3;
    /**
    * Next execution time for this task in the format returned by
    * System.currentTimeMillis, assuming this task is scheduled for execution.
    * For repeating tasks, this field is updated prior to each task execution.
    */
    long nextExecutionTime;
    /**
    * Period in milliseconds for repeating tasks.
    A positive value indicates
    * fixed-rate execution.
    A negative value indicates fixed-delay execution.
    * A value of 0 indicates a non-repeating task.
    */
    long period = 0;
    /**
    * Creates a new timer task.
    */
    protected TimerTask() {
    }
    /**
    * The action to be performed by this timer task.
    */
    public abstract void run();
    /**
    * Cancels this timer task.
    If the task has been scheduled for one-time
    * execution and has not yet run, or has not yet been scheduled, it will
    * never run.
    If the task has been scheduled for repeated execution, it
    * will never run again.
    (If the task is running when this call occurs,
    * the task will run to completion, but will never run again.)
    *
    * <p>Note that calling this method from within the <tt>run</tt> method of
    * a repeating timer task absolutely guarantees that the timer task will
    * not run again.
    *
    * <p>This method may be called repeatedly; the second and subsequent
    * calls have no effect.
    *
    * @return true if this task is scheduled for one-time execution and has
    *
    not yet run, or this task is scheduled for repeated execution.
    *
    Returns false if the task was scheduled for one-time execution
    *
    and has already run, or if the task was never scheduled, or if
    *
    the task was already cancelled.
    (Loosely speaking, this method
    *
    returns <tt>true</tt> if it prevents one or more scheduled
    *
    executions from taking place.)
    */
    public boolean cancel() {
    synchronized(lock) {
    boolean result = (state == SCHEDULED);
    state = CANCELLED;
    return result;
    }
    }
    /**
    * Returns the <i>scheduled</i> execution time of the most recent
    * <i>actual</i> execution of this task.
    (If this method is invoked
    * while task execution is in progress, the return value is the scheduled
    * execution time of the ongoing task execution.)
    *
    * <p>This method is typically invoked from within a task's run method, to
    * determine whether the current execution of the task is sufficiently
    * timely to warrant performing the scheduled activity:
    * <pre>{@code
    *
    public void run() {
    *
    if (System.currentTimeMillis() - scheduledExecutionTime() >=
    *
    MAX_TARDINESS)
    *
    return;
    // Too late; skip this execution.
    *
    // Perform the task
    *
    }
    * }</pre>
    * This method is typically <i>not</i> used in conjunction with
    * <i>fixed-delay execution</i> repeating tasks, as their scheduled
    * execution times are allowed to drift over time, and so are not terribly
    * significant.
    *
    * @return the time at which the most recent execution of this task was
    *
    scheduled to occur, in the format returned by Date.getTime().
    *
    The return value is undefined if the task has yet to commence
    *
    its first execution.
    * @see Date#getTime()
    */
    public long scheduledExecutionTime() {
    synchronized(lock) {
    return (period < 0 ? nextExecutionTime + period
    : nextExecutionTime - period);
    }
    }
    }

最后

以上就是眼睛大秀发为你收集整理的开启异步线程保存登录日志信息的全部内容,希望文章能够帮你解决开启异步线程保存登录日志信息所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部