zoukankan      html  css  js  c++  java
  • 【原】基于代理实现类似 Spring @Async异步组件

       最近在工作中使用到了spring自带的@Async,主要是为了把其中耗时多、响应慢、计算复杂的业务抽出来查询。从代码设计上看Spring自带的比传统线程池提交在代码层次上看起来优雅简洁了不少,无需显示去申明线程池相关代码, 在方法上加注解既可异步返回结果。空闲时间大概看了下原理,其实就是代理模式(cglib or 接口), 刚好最近学习到线程和并发相关的jdk组件,今天就打算自己手动实现这个异步组件。

         总体实现思路流程:客户端调用后-》通过代理模式代理-》重写Submit方法并返回Future-》把Future 放到自定义的异步返回包装类-》客户端直接拿到返回的Future 进行阻塞get

    流程图:

    以下是接口代理实现,至于Cglib代理实现和接口代理原理是一致的,可以自行实现。

    1.新建代理接口


    public interface IAsyncProxy {
    
        /**
         * 获取代理对象
         * 1. 如果是实现了接口,默认使用 dynamic proxy 即可。
         * 2. 如果没有实现接口,默认使用 CGLIB 实现代理。
         * @return 代理对象
         */
        Object proxy();
    
    }
    

    2.新建动态代理实现类

    public class DynamicProxy implements InvocationHandler, IAsyncProxy {
    
        /**
         * 被代理的对象
         */
        private final Object target;
    
        public DynamicProxy(Object target) {
            this.target = target;
        }
    
        /**
         *
         *
         * @param proxy 原始对象
         * @param method 方法
         * @param args 入参
         * @return 结果
         * @throws Throwable 异常
         */
        @Override
        @SuppressWarnings("all")
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return AsyncExecutor.submit(target, method, args);
        }
    
        @Override
        public Object proxy() {
            // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
            InvocationHandler handler = new DynamicProxy(target);
    
            return Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                    target.getClass().getInterfaces(), handler);
        }
    }
    

     其中最主要的是代理之后我们要如何交给异步处理,在invoke方法内,我通过线程池去提交任务,细心的可以发现AsyncExecutor在jdk包里是没有的,这个类是我自己定义的。至于原因有以下几个:

            1.jdk自带的ExecutorService的submit无法满足现有功能, 所以需要重新实现ExecutorService做扩展,重写submit方法。

            2.submit之后需要包装统一的返回结果

    3.定义异步接口

    /**
     * <p> 异步执行结果 </p>
     /
    public interface IAsyncResult<T> extends Future<T> {
    
        /**
         * 获取执行的结果
         * @return 结果
         */
        Object getResult();
    
    }
    

      

    抽象的异步返回类

    public abstract class AbstractAsyncResult<T> implements IAsyncResult<T> {
    
        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            return false;
        }
    
        @Override
        public boolean isCancelled() {
            return false;
        }
    
        @Override
        public boolean isDone() {
            return false;
        }
    
        @Override
        public T get() throws InterruptedException, ExecutionException {
            try {
                return this.get(AsyncConstant.DEFAULT_TIME_OUT, TimeUnit.SECONDS);
            } catch (TimeoutException e) {
                throw new RuntimeException(e);
            }
        }
    
    }
    

      

    返回结果类

    /**
     * 异步执行结果
    
     */
    public class AsyncResult<T> extends AbstractAsyncResult<T> {
    
        /**
         * future 信息
         */
        private Future<T> future;
    
        /**
         * 结果
         */
        private Object value;
    
        /**
         * 获取执行的结果
         * @return 结果
         */
        @Override
        public Object getResult() {
            // 直接返回结果
            if(future == null) {
                return this.getValue();
            }
    
            try {
                T t = future.get();
                // 这里拿到的 AsyncResult 对象
                if(null != t) {
                    return ((AsyncResult)t).getValue();
                }
                return null;
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            return future.get(timeout, unit);
        }
    
        public Object getValue() {
            return this.value;
        }
    
        public void setValue(Object value) {
            this.value = value;
        }
    
        public void setFuture(Future<T> future) {
            this.future = future;
        }
    
    }
    

      

    4.定义一个异步接口,继承ExecutorService 

    /**
     * <p> 异步框架执行器 </p>
    */
    public interface IAsyncExecutor extends ExecutorService {
    }
    
    /**
     * 异步执行器
     */
    public class AsyncExecutor extends ThreadPoolExecutor implements IAsyncExecutor {
    
        //region 私有属性
        /**
         * 是否初始化
         */
        private static volatile boolean isInit = false;
    
        /**
         * 是否被销毁
         */
        private static volatile boolean isDestroy = false;
    
        /**
         * 线程执行器
         */
        private static ExecutorService executorService = null;
        //endregion
    
        //region 构造器
        public AsyncExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }
    
        public AsyncExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        }
    
        public AsyncExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        }
    
        public AsyncExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        }
        //endregion
    
        @SuppressWarnings("all")
        public static <T> IAsyncResult<T> submit(Object target, Method method, Object[] objects) {
            // 初始化的判断
            if(!isInit) {
                init();
            }
            //通过线程池提交
            Future future =  executorService.submit(new Runnable() {
    			@Override
    			public void run() {
    				try {
    					method.invoke(target, objects);
    				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		});
    
            //Future future = executorService.submit(() -> method.invoke(target, objects));
            
            AsyncResult<T> asyncResult = new AsyncResult<>();
            asyncResult.setFuture(future);
            return asyncResult;
        }
    
        /**
         * 初始化
         * 1. 暂时不添加配置相关的信息
         * 2. 最后调整状态
         */
        private static synchronized void init() {
            try {
                if(isInit) {
                    return;
                }
    
                // 各种属性配置
                // 淘汰策略
                // 最佳线程数量
                executorService = Executors.newFixedThreadPool(10);
                updateExecutorStatus(true);
            } catch (Exception e) {
                throw new AsyncRuntimeException(e);
            }
        }
    
        /**
         * 销毁容器
         * 1. 销毁的时候进行等待,确保任务的正常执行完成。
         * 2. 任务执行的统计信息,后期添加。
         */
        private static synchronized void destroy() {
            if(isDestroy) {
                return;
            }
    
            executorService = null;
            updateExecutorStatus(false);
        }
    
        /**
         * 更新执行器的状态
         * @param initStatus 初始化状态
         */
        private static void updateExecutorStatus(final boolean initStatus) {
            isInit = initStatus;
            isDestroy = !isInit;
        }
    }
    

      

     

    总结:

      以上代码最核心的就是通过动态代理在内部通过线程池异步提交,以及重写jdk的线程池也是为了能够重写内部核心方法

  • 相关阅读:
    JDK里面包含jre,为什么还要下载一个jre呢?
    2021年11月2日,面试经历
    linux内核学习心得
    关于QQ短信接口的使用。
    软件测试--开发者测试例子
    此博客相关声明·AP2017060911I
    21RNC201906034I·代码重构
    20RNC201901313I·代码重构
    19RND201808172·层次设定
    18RND201801311·图像方案日记
  • 原文地址:https://www.cnblogs.com/zdd-java/p/10918311.html
Copyright © 2011-2022 走看看