1、Spring异步任务
开启异步配置(@EnableAsync注解指定或<task:annotation-driven>标签配置)
1、用Java注解:
第一步:在类的申明前使用@EnableAsync注解开启异步调用功能。
第二步:public AsyncTaskExecutor taskExecutor() 方法自定义自己的线程池,线程池前缀”Anno-Executor”。如果不定义,则使用系统默认的线程池。
@EnableAsync // 启动异步调用
public class AsyncApplicationWithAnnotation {
/* 略 */
/**
* 自定义异步线程池
* @return
*/
@Bean
public AsyncTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("Anno-Executor");
executor.setMaxPoolSize(10);
// 设置拒绝策略
executor.setRejectedExecutionHandler(new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// .....
}
});
return executor;
}
}
2、用XML配置:
第一步:使用<task:executor>标签定义线程池
第二步:使用<task:annotation-driven>标签启动异步线程池配置
如下spring-async.xml配置:
<!-- 等价于 @EnableAsync, executor指定线程池 --> <task:annotation-driven executor="xmlExecutor"/> <!-- id指定线程池产生线程名称的前缀 --> <task:executor id="xmlExecutor" pool-size="5-25" queue-capacity="100" keep-alive="120" rejection-policy="CALLER_RUNS"/>
有关线程池的拒绝策略,参考下文:
线程池--拒绝策略RejectedExecutionHandler
编写异步任务(@Async注解指定)
1、编写普通Java类,并设置方法为@Async注解
只需要简单这么一步即可在执行注解方法时自动由Spring框架执行异步操作。
p
ackage tech.bbwang.springtask.scheduled.demo;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class ScheduledTaskExample {
public ScheduledTaskExample(){
}
@Async
public void printTime(){
System.out.println((new Date()).toString());
}
}
2、线程池
配置线程池
最简单的形式,只需要在spring配置文件里加一条配置即可。
<task:executor id="xmlExecutor" pool-size="2" />
添加此配置需要在Spring配置文件的<beans>头部添加下面的约束文件(task相关处的命名空间)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
使用线程池
线程池xmlExecutor作为一个Spring的bean存在,可以被注入到需要的地方。
比如:
定义一个使用线程池的类TaskExecutorExample,该类使用线程池跑10个打印当前时间的任务。
package tech.bbwang.springtask.demo;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import tech.bbwang.App;
import java.util.HashMap;
import java.util.Map;
/**
* 任务执行样例
*/
@Component
public class TaskExecutorExample
{
private TaskExecutor taskExecutor;
public TaskExecutorExample(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void printMessages() {
for(int i = 0; i <10; i++) {
taskExecutor.execute(new Runnable(){
public void run(){
System.out.println((new Date()).toString());
}
});
}
}
}
Spring配置文件设置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="tech.bbwang.springtask.demo"/>
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
<bean id="taskExecutorExample" class="tech.bbwang.springtask.demo.TaskExecutorExample">
<constructor-arg ref="taskExecutor" />
</bean>
</beans>
3、定时器和定时任务
定义定时器
spring配置文件:
<!-- pool-size:此参数默认为1,此时,不同的定时任务不可同时进行,因为线程数不够。需要自己设置>1的数值来保证,同一个定时任务前一个未完成情况下不启动下一个,但不用的定时任务可以同时进行-->
<task:scheduler id="taskScheduler" pool-size="10"/>
定义定时任务
spring配置文件:
<task:scheduled-tasks>
<!-- 配置定时任务,cron=一秒一次-->
<task:scheduled ref="scheduledTaskExample" method="printTime" cron="0/5 * * * * ?"/>
<!-- 配置定时任务,cron=每日0时和12时各执行一次任务-->
<!--Cron表达式生成器 http://www.pdtools.net/tools/becron.jsp-->
<!--<task:scheduled ref="scheduledTaskExample" method="printTime" cron="0/1 0/1 0,12 * * ?"/>-->
</task:scheduled-tasks>
有关corn表达式可以参考:
cron表达式详解
定义定时任务类
package tech.bbwang.springtask.scheduled.demo;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class ScheduledTaskExample {
public ScheduledTaskExample(){
}
@Async
public void printTime(){
System.out.println((new Date()).toString());
}
}
定义运行类
其实已经完全由Spring配置解决了运行问题,只需要给一个运行Spring配置的主函数即可。
package tech.bbwang;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.concurrent.CountDownLatch;
public class SpringAsyncTask {
public static void main( String[] args )
{
new ClassPathXmlApplicationContext("spring-async*.xml");
}
}