【原】手写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的线程池也是为了能够重写内部核心方法
【原】手写spring async异步组件的更多相关文章
- 手写Spring MVC
闲及无聊 又打开了CSDN开始看一看有什么先进的可以学习的相关帖子,这时看到了一位大神写的简历装X必备,手写Spring MVC. 我想这个东西还是有一点意思的 就拜读了一下大佬的博客 通读了一遍相关 ...
- 手写Spring事务框架
Spring事务基于AOP环绕通知和异常通知 编程事务 声明事务 Spring事务底层使用编程事务+AOP进行包装的 = 声明事务 AOP应用场景: 事务 权限 参数验证 什么是AOP技术 AO ...
- Spring学习之——手写Spring源码V2.0(实现IOC、D、MVC、AOP)
前言 在上一篇<Spring学习之——手写Spring源码(V1.0)>中,我实现了一个Mini版本的Spring框架,在这几天,博主又看了不少关于Spring源码解析的视频,受益匪浅,也 ...
- 手写spring
体系结构 Spring 有可能成为所有企业应用程序的一站式服务点,然而,Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入.下面的部分对在 Spring 框架中所有可用的 ...
- 手写Spring AOP,快来瞧一瞧看一看撒!
目录 AOP分析 Advice实现 定义Advice接口 定义前置.后置.环绕和异常增强接口 Pointcut实现 定义PointCut接口 定义正则表达式的实现类:RegExpressionPoin ...
- 一个老程序员是如何手写Spring MVC的
人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...
- 【Spring】手写Spring MVC
Spring MVC原理 Spring的MVC框架主要由DispatcherServlet.处理器映射.处理器(控制器).视图解析器.视图组成. 完整的Spring MVC处理 流程如下: Sprin ...
- 我是这样手写 Spring 的(麻雀虽小五脏俱全)
人见人爱的 Spring 已然不仅仅只是一个框架了.如今,Spring 已然成为了一个生态.但深入了解 Spring 的却寥寥无几.这里,我带大家一起来看看,我是如何手写 Spring 的.我将结合对 ...
- 《四 spring源码》利用TransactionManager手写spring的aop
事务控制分类 编程式事务控制 自己手动控制事务,就叫做编程式事务控制. Jdbc代码: Conn.setAutoCommite(false); // 设置手动控制事务 Hibern ...
随机推荐
- leetcode-24-exercise
506. Relative Ranks 解题思路: 使用priority_queue.它在插入时会将数据按照由大到小的顺序插入,自然排序了.所以插入时考虑插入pair<nums[i],i> ...
- $(MAKE) , make命令
make 定义了很多默认变量,像常用的命令或者是命令选项之类的,什么CC啊,CFLAGS啊之类.$(MAKE)就是预设的 make 这个命令的名称(或者路径).make -p 可以查看所有预定义的变量 ...
- LeetCode(292) Nim Game
题目 You are playing the following Nim Game with your friend: There is a heap of stones on the table, ...
- Cheese Aizu - 0558 (搜索题)
Time limit8000 ms Memory limit131072 kB チーズ () 問題 今年も JOI 町のチーズ工場がチーズの生産を始め,ねずみが巣から顔を出した.JOI 町は東西南北に ...
- poj 1321 排兵布阵问题 dfs算法
题意:有不规则地图,在上面放n个相同的棋子,要求摆放的时候不同行不同列.问:有多少种摆法? 思路:dfs+回溯 用一个book[]数组来表示当前列是否有放棋子 一行一行的遍历,对一行来说遍历它的列,如 ...
- PAT Basic 1076
1076 Wifi密码 下面是微博上流传的一张照片:“各位亲爱的同学们,鉴于大家有时需要使用 wifi,又怕耽误亲们的学习,现将 wifi 密码设置为下列数学题答案:A-1:B-2:C-3:D-4:请 ...
- pidgin中使用QQ
安装 实现的功能: 可以发送静态表情 可以发送动态表情 可以发图片? 可以添加好友 可以添加群?
- jmeter switch controller
工作方式: Switch控制器通过给该控制器中的Value赋值,来指定运行哪个采样器.有两种赋值方式: 1.第一种是数值,Switch控制器下的子节点从0开始计数,通过指定子节点所在的数值来确定执行哪 ...
- Python之多线程与多进程(二)
多进程 上一章:Python多线程与多进程(一) 由于GIL的存在,Python的多线程并没有实现真正的并行.因此,一些问题使用threading模块并不能解决 不过Python为并行提供了一个替代方 ...
- 光学字符识别OCR-6 光学识别
经过前面的文字定位和文本切割,我们已经能够找出图像中单个文字的区域,接下来可以建立相应的模型对单字进行识别. 模型选择 在模型方面,我们选择了深度学习中的卷积神经网络模型,通过多层卷积 ...