【原】手写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 ...
随机推荐
- urllib、requests库整理
- LeetCode(129) Sum Root to Leaf Numbers
题目 Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a num ...
- JAVA里的别名机制
别名现象主要出现在赋值的问题上: 对基本数据类型的赋值是很简单的.基本数据类型存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方.例如,对基本数 ...
- UVa 11695 树的直径 Flight Planning
题意: 给出一棵树,删除一条边再添加一条边,求新树的最短的直径. 分析: 因为n比较小(n ≤ 2500),所以可以枚举删除的边,分裂成两棵树,然后有这么一个结论: 合并两棵树后得到的新树的最短直径为 ...
- dubbo doc入门文档
dubbo document http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-protocol.html
- 光学字符识别OCR-5 文本切割
经过前面文字定位得到单行的文本区域之后,我们就可以想办法将单行的文本切割为单个的字符了.因为第三步的模型是针对单个的字符建立的,因此这一步也是必须的. 均匀切割 基于方块汉字的假设,事实上最简单的切割 ...
- 光学字符识别OCR-2
灰度聚类 接着我们就对图像的色彩进行聚类.聚类的有两个事实依据: 1.灰度分辨率 肉眼的灰度分辨率大概为40,因此对于像素值254和255,在我们肉眼看来都 只是白色: ...
- ogre3D学习基础11 -- 日志文件的使用与异常处理
用文件来记录 Ogre 系统初始化.运行.结束以及调试信息.使用日志便于我们调试程序.Ogre 日志系统由两个类组成:Log 类与 LogManager. 1.Log类 Log 类的一个对象对应于一个 ...
- [uiautomator篇][1] 官网译文
http://www.jianshu.com/p/7718860ec657 2016.07.25 20:59 字数 3675 Android UIAutomator浅谈 --------------- ...
- IO Streams:字符流
简介 Java平台使用Unicode约定存储字符值.字符流I / O自动将此内部格式转换为本地字符集.在西方,本地字符集通常是ASCII的8位超集. 对于大多数应用,具有字符流的I / O并不比具有字 ...