开启异步线程保存登录日志信息

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

  • 关键词:单例模式,异步管理器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);
            }
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
CompletableFuture是Java 8引入的一个类,用于支持异步编程和处理异步任务的结果。它提供了一种简洁而强大的方式来开启异步线程。 要使用CompletableFuture开启异步线程,可以按照以下步骤进行操作: 1. 创建一个CompletableFuture对象:可以使用CompletableFuture的静态方法`supplyAsync()`或`runAsync()`来创建一个CompletableFuture对象。`supplyAsync()`用于执行有返回值的异步任务,`runAsync()`用于执行没有返回值的异步任务。 2. 定义异步任务:使用`thenApply()`、`thenAccept()`或`thenRun()`等方法来定义异步任务。这些方法接受一个函数作为参数,用于处理异步任务的结果。 3. 处理异步任务的结果:可以使用`get()`方法来获取异步任务的结果,或者使用`join()`方法来等待异步任务完成并获取结果。也可以使用`thenApply()`、`thenAccept()`或`thenRun()`等方法来处理异步任务的结果。 下面是一个示例代码,演示了如何使用CompletableFuture开启异步线程: ```java import java.util.concurrent.CompletableFuture; public class CompletableFutureExample { public static void main(String[] args) { // 创建CompletableFuture对象,并开启异步线程执行任务 CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { // 异步任务的逻辑 return "Hello, CompletableFuture!"; }); // 处理异步任务的结果 future.thenApply(result -> { // 处理异步任务的结果 System.out.println(result); return result.toUpperCase(); }).thenAccept(result -> { // 处理上一步的结果 System.out.println("Uppercase result: " + result); }); // 等待异步任务完成 future.join(); } } ``` 以上代码中,首先使用`supplyAsync()`方法创建了一个CompletableFuture对象,并在其中定义了一个异步任务,该任务返回字符串"Hello, CompletableFuture!"。然后使用`thenApply()`方法处理异步任务的结果,将结果转换为大写并输出。最后使用`join()`方法等待异步任务完成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值