SpringHome

spring 的 @Async 异步任务配置 及事务的说明

2018-09-19  本文已影响204人  天天向丶上

最近涉及到了一些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里面加上事务吧。

上一篇 下一篇

猜你喜欢

热点阅读