最近涉及到了一些spring的异步任务的了解,虽然我没去写相关的代码,不过还是去了解了很多,此处做一些记录。
spring异步任务配置
在spring的配置文件之中,增加task的配置,包含相关的约束的引用和相关的设置。
具体如下:在xmlns中添加task,在xsi中加入具体的约束地址。增加
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation=http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd
增加task的配置,这里可能有小伙伴配置过spring定时就会发现,配置是一个,其也确实是一个,看了下约束,里面说的很清楚,是给定时的注释和异步任务的注释使用的。
Enables the detection of @Async and @Scheduled annotations on any Spring-managed
object.
<task:annotation-driven executor="threadPoolTaskExecutor" />
这里说明下,连接池是自己配置的,因为有别的需求,官方的说明如下:
Specifies the java.util.Executor instance to use when invoking asynchronous methods.
If not provided, an instance of org.springframework.core.task.SimpleAsyncTaskExecutor
will be used by default.
然后具体的连接池配置如下:
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!--核心线程数,默认为1 -->
<property name="corePoolSize" value="10" />
<!--最大线程数,默认为Integer.MAX_VALUE-->
<property name="maxPoolSize" value="50" />
<!--队列最大长度,一般需要设置值>=notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE-->
<property name="queueCapacity" value="1000" />
<!--线程池维护线程所允许的空闲时间,默认为60s-->
<property name="keepAliveSeconds" value="300" />
<!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者-->
<property name="rejectedExecutionHandler">
<!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常-->
<!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度-->
<!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行-->
<!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行-->
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
<!-- 线程关闭策略,默认false,当值为true时,只有当子线程里面的任务完成时才会调用shutdown()来关闭现场 -->
<property name="waitForTasksToCompleteOnShutdown" value="true" />
</bean>
到这里,配置方面已经说清楚了,下面说下使用吧。
spring异步任务执行
使用很简单 ,在service里面,需要异步执行的方法,添加@Async这个注释即可,,这个任务就会异步执行。
代码如下:
@Service
public class TestServiceImpl implements TestService {
@Async
@Override
public void runTheTest(){
System.out.println("执行11111");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行22222");
}
}
spring异步任务的事务
说到事务就毕竟麻烦,之前网上查了一下,说不能直接在这个异步任务里面直接加事务,需要引用其他service里面的加事务。项目本身是aop来进行事务的管理,然后再service里面引入了两个其他的service。
代码入下:
@Service
public class TestServiceImpl implements TestService {
@Autowired
private BigDataMessageService bigDataMessageService;
private SqCoursewareService sqCoursewareService;
@Async
@Override
public void runTheTest(){
System.out.println("执行11111");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
List<WarningMessage> messageList = new ArrayList<WarningMessage>();
WarningMessage a = new WarningMessage();
a.setUnitId("999");
a.setUserId("000");
a.setCreationTime(new Date());
a.setMessage("999000");
a.setType(1);
a.setResult("000999");
messageList.add(a);
bigDataMessageService.insertWarningMessage(messageList);
sqCoursewareService.selectByPrimaryKey(1);
}
}
这里第二个service实际没有注入,所以运行实际这个方法会报空指针异常。首先屏蔽掉 sqCoursewareService.selectByPrimaryKey(1);
这个方法,结果正常插入。
之后解除屏蔽,抛出了空指针异常,同时插入的数据被回滚。
本身单个没有引用有事务的service,测试结果实际也是被回滚了。
代码如下:
@Service
public class TestServiceImpl implements TestService {
@Autowired
private BigDataMessageMapper bigDataMessageMapper;
@Async
@Override
public void runTheTest(){
System.out.println("执行11111");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
List<WarningMessage> messageList = new ArrayList<WarningMessage>();
WarningMessage a = new WarningMessage();
a.setUnitId("991");
a.setUserId("001");
a.setCreationTime(new Date());
a.setMessage("991001");
a.setType(1);
a.setResult("001991");
messageList.add(a);
bigDataMessageMapper.insertWarningMessage(messageList);
Integer.valueOf(testFunction());
System.out.println("执行222222");
}
private String testFunction(){
return null;
}
}
这里直接引入Mapper,Mapper实际是没有事务的,然后
Integer.valueOf(testFunction());
这里会抛异常,结果是插入同样被回滚了。
也许网上说的情况和我测试的不一致,也许是spring版本的原因,这里时间有限没有进一步的测试了。小伙伴如果知道是哪里有问题可以告诉我下,然后写的话,尽量本身不要涉及事务,然后引用的service里面加上事务吧。