叮咚!今晚我想来点可不可的.....,不对,是Async,这是在Spring 2.2.4 所提倡非同步注解模式(@Async),在这之前呢,大部分使用者都是采用Thread,Runnable及Callable这三种方法进去建立执行绪达到非同步效果,这样的写法到产出许多笨重且难以维护的程序码,此时Spring @Async进行以提倡新的写法,可将所有非同步方法包装在一个服务(@Service)内,透过每个方法回传非同步物件(AsyncResult)提供於客户端进行获取值使用,每个方法都透过Future介面实现,在java.util.concurrent包中。Future介面是Java执行绪Future模式的实现,可以来进行非同步计算,透过此种方式方便注入个式领域服务(Domain service)中进行触发对应的执行绪,可达到更简便的方式进行非同步工作效益,现在运送员小编将快速将这个套件功能送到你脑袋中。
每个异步处理程序(@Async)相当於创建一只新的子执行绪(Thread),并自己独立执行一项任务,父执行绪会循序等待每个子执行绪执行完任务,并获取相关物件值,再次进行相关逻辑运算後,才会回传最终结果,以下范例读者可进行参考,可进一步了解相关运作原理。
步骤一、配置执行绪池设定档
spring.task.pool.corePoolSize = 5
spring.task.pool.maxPoolSize = 50
spring.task.pool.keepAliveSeconds= 60
spring.task.pool.queueCapacity = 10000
spring.task.pool.threadNamePrefix = Wesiting-Thread-
步骤二、将配置组态模型,并将值注入模型中
@Configuration
@ConfigurationProperties(prefix = "spring.task.pool")
public class TaskThreadPoolConfig {
private int corePoolSize = 5;
private int maxPoolSize = 50;
private int keepAliveSeconds = 60;
private int queueCapacity =10000;
private String threadNamePrefix = "Weisting-AsyncTask-";
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getKeepAliveSeconds() {
return keepAliveSeconds;
}
public void setKeepAliveSeconds(int keepAliveSeconds) {
this.keepAliveSeconds = keepAliveSeconds;
}
public int getQueueCapacity() {
return queueCapacity;
}
public void setQueueCapacity(int queueCapacity) {
this.queueCapacity = queueCapacity;
}
public String getThreadNamePrefix() {
return threadNamePrefix;
}
public void setThreadNamePrefix(String threadNamePrefix) {
this.threadNamePrefix = threadNamePrefix;
}
}
步骤三、配置非同步服务,将每个方法配置Future介面,并回传AsyncResult封装物件。
Service
public class AsyncCaller {
Logger logger = LoggerFactory.getLogger(AsyncCaller.class);
@Async
public Future<SeaFood> asyncSeaFoodWithReturnTypeFromTaiwan(String id) {
System.out.println("Execute taiwan's async method asynchronously - "
+ Thread.currentThread().getName());
try {
Thread.sleep(5000);
SeaFood seaFood = SEA_FOOD_CACHE_TAIWAN.asMap().getOrDefault(id,null);
return new AsyncResult<SeaFood>(seaFood);
} catch (InterruptedException e) {
logger.error("InterruptedException : {}",e.toString() );
}
return null;
}
@Async
public Future<SeaFood> asyncSeaFoodWithReturnTypeFromChina(String id) {
System.out.println("Execute china's async method asynchronously - "
+ Thread.currentThread().getName());
try {
Thread.sleep(5000);
SeaFood seaFood = SEA_FOOD_CACHE_CHINESE.asMap().getOrDefault(id,null);
return new AsyncResult<SeaFood>(seaFood);
} catch (InterruptedException e) {
logger.error("InterruptedException : {}",e.toString() );
}
return null;
}
}
步骤四、注入非同步服务,并触发後,并等待任务完成後进行获取相关物件值,以便进行回传。此段写法与各位开发者早期Future-Callable写法相同,可进行参考。
@Autowired
AsyncCaller asyncCaller;
public SeaFood testAsyncAnnotationForMethodsWithReturnSeaFood(LocationEnum locationEnum,String id)
throws InterruptedException, ExecutionException {
System.out.println("Invoking an asynchronous method. "
+ Thread.currentThread().getName());
Future<SeaFood> future = null;
if (locationEnum == LocationEnum.TAIWAN)
future = asyncCaller.asyncSeaFoodWithReturnTypeFromTaiwan(id);
else
future = asyncCaller.asyncSeaFoodWithReturnTypeFromChina(id);
while (true) {
if (future.isDone()) {
return future.get();
}
System.out.println("Continue doing something else. Waiting... ");
Thread.sleep(1000);
}
}
根据触发Find Taiwan product API後,会跟上续结果一样等待五秒後才接收到回传结果。
//Log
Invoking an asynchronous method. http-nio-8080-exec-1
Continue doing something else. Waiting...
Execute taiwan's async method asynchronously - Wesiting-Thread-1
Continue doing something else. Waiting...
Continue doing something else. Waiting...
Continue doing something else. Waiting...
Continue doing something else. Waiting...
Continue doing something else. Waiting...
透过以上范例与原理,小编在这边相当推荐给大家做使用,非常简便又快速,是种不错的好方法。
其运作方式皆是透过我们先前所叙的CGLIB切面式编程框架进行代理,由下图每个Bean类型我们可得知,此监测GUI为运送员小编抽空开发,最後一天会开源给大家做参考引用,先行提供给大家参考。
如图一所示,在预设的情况下会自动透过代理程序创建一个AsyncAnnotationBeanPostProcessor处理器,无论是何种处理器都会间接时间BeanFactoryAware此接口,并在实例化的方法(setBeanFactory)中,除了设置BeanFactory之外,也创建一个Async注解模式的处理器(AsyncAnnotationAdvisor),透过图二我们可进一步的了解其构造。
图一、AsyncAnnotationBeanPostProcessor启动关系流程图
由下图可得知,在AsyncAnnotationAdvisor进行建构子初始化时,会建立执行绪与异常拦截器(AnnotationAsyncExecutionInterceptor),及根据@Async注解位置建立切入点(AnnotationMatchingPointcut)触发元件,可以看到非同步触发拦截器(AnnotationAsyncExecutionInterceptor)间接实现了方法拦截器(MethodInterceptor)接口,而方法拦截器(MethodInterceptor)是AOP切入点处理器,处理器中最终被触发的是invoke方法,即可进行触发开发者所配置类别中的Future方法,并回传AsyncResult结果物件值,即可达到使用者预期效果。
图二、Async核心运作流程图
Spring Boot(5) @Async非同步执行绪池详解
<<: 找LeetCode上简单的题目来撑过30天啦(DAY22)
hi~我们今天要讨论有关solidity合约内容,今天的内容会延续昨天的!所以如果还没看昨天的建议...
Spark 支援批次资料、查询分析、资料流、机器学习及图处理(Graph Processing),...
图片来源:https://3c.ltn.com.tw/news/45392 现在已经是人手一机的时...
今天即将进入 Caching & Networking 章节的第一天,快取,是一个非常重要...
现在不管是学校课程规划或是同学主动想要了解职场,对於实习其实是一个可以看清自己的能力跟业界之间的差距...