最近在工作中使用到了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的线程池也是为了能够重写内部核心方法

【原】手写spring async异步组件的更多相关文章

  1. 手写Spring MVC

    闲及无聊 又打开了CSDN开始看一看有什么先进的可以学习的相关帖子,这时看到了一位大神写的简历装X必备,手写Spring MVC. 我想这个东西还是有一点意思的 就拜读了一下大佬的博客 通读了一遍相关 ...

  2. 手写Spring事务框架

    Spring事务基于AOP环绕通知和异常通知 编程事务 声明事务 Spring事务底层使用编程事务+AOP进行包装的   = 声明事务 AOP应用场景:  事务 权限 参数验证 什么是AOP技术 AO ...

  3. Spring学习之——手写Spring源码V2.0(实现IOC、D、MVC、AOP)

    前言 在上一篇<Spring学习之——手写Spring源码(V1.0)>中,我实现了一个Mini版本的Spring框架,在这几天,博主又看了不少关于Spring源码解析的视频,受益匪浅,也 ...

  4. 手写spring

    体系结构 Spring 有可能成为所有企业应用程序的一站式服务点,然而,Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入.下面的部分对在 Spring 框架中所有可用的 ...

  5. 手写Spring AOP,快来瞧一瞧看一看撒!

    目录 AOP分析 Advice实现 定义Advice接口 定义前置.后置.环绕和异常增强接口 Pointcut实现 定义PointCut接口 定义正则表达式的实现类:RegExpressionPoin ...

  6. 一个老程序员是如何手写Spring MVC的

    人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...

  7. 【Spring】手写Spring MVC

    Spring MVC原理 Spring的MVC框架主要由DispatcherServlet.处理器映射.处理器(控制器).视图解析器.视图组成. 完整的Spring MVC处理 流程如下: Sprin ...

  8. 我是这样手写 Spring 的(麻雀虽小五脏俱全)

    人见人爱的 Spring 已然不仅仅只是一个框架了.如今,Spring 已然成为了一个生态.但深入了解 Spring 的却寥寥无几.这里,我带大家一起来看看,我是如何手写 Spring 的.我将结合对 ...

  9. 《四 spring源码》利用TransactionManager手写spring的aop

    事务控制分类 编程式事务控制          自己手动控制事务,就叫做编程式事务控制. Jdbc代码: Conn.setAutoCommite(false);  // 设置手动控制事务 Hibern ...

随机推荐

  1. python数据类型之字符串(str)和其常用方法

    字符串是有序的,不可变的. 下面的例子说明了字符串是不可变的 name = 'alex' name = 'Jack' """ 并没有变,只是给name开启了一块新内存,储 ...

  2. 库函数的使用:POJ1488-TEX Quotes(getline()的使用)

    TEX Quotes Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9385 Description TEX is a type ...

  3. ACM 深度优化搜索算法小总结

    深度优化搜索算法的本质:就是从一状态不断转移,如果无法转移了就需要返回上一个状态,知道找到解为止. 其核心:递归函数 基本模型: dfs(int i, int j) { //控制结束条件 //进行状态 ...

  4. [转载] C语言细节,写的非常棒!

    这篇文章主要讨论C语言细节问题.在找一份工作的时候,语言细节占的比例非常小,之前看某个贴着讨论,估计语言细节在面试中,占了10%的比重都不到,那为什么还要研究C语言的细节呢,我觉得有三个原因促使我总结 ...

  5. myeclipse中hibernate生成映射文件

    在hibernate中,每个数据表对应的其实是一个实体类,每个实体类有一个对应的hbm.xml配置文件匹配,myeclipse中有个MyEclipse Database Explorer视图,它提供了 ...

  6. T-SQL中的indexof函数

    在C#字符串中查找字符有indexof方法,那么在T-SQL与之相对应的是CHARINDEX方法,其语法为CHARINDEX(要查找的字符,字符串),返回一个数字. CHARINDEX(',','aa ...

  7. oracle 控制文件的重建

    目录 oracle 控制文件的重建 NORESETLOGS RESETLOGS oracle 控制文件的重建 不到最后时刻,如三个控制文件都已损坏,又没有控制文件的备份.还是不要重建控制文件,处理不好 ...

  8. python + selenium + unittest 自动化测试框架 -- 入门篇

    . 预置条件: 1. python已安装 2. pycharm已安装 3. selenium已安装 4. chrome.driver 驱动已下载 二.工程建立 1. New Project:建立自己的 ...

  9. Pandas对多列进行升降序排列

    df = pd.DataFrame(rows, columns = ["llx", "lly", "urx", "ury" ...

  10. java EE技术体系——CLF平台API开发注意事项(1)——后端开发

    前言:这是一篇帮助小伙伴在本次项目中快速进入到java EE开发的一些说明,为了让同组小伙伴们开发的时候,有个清晰点的思路.昨天给大家演示分享了基本概况,但没有留下文字总结说明,预防后期有人再次问我, ...