当我们需要在Spring应用中增加异步任务支持时,可以使用@Async注解来标示异步方法。@Async注解可以标识在任何方法上面,表示该方法会异步执行。本篇攻略将从以下几个方面介绍Spring中@Async的用法,包括:
- 开启异步支持
- 使用@Async注解实现异步方法
- 使用Future返回异步结果
- 示例1:异步方法的实现
- 示例2:带参数的异步方法
开启异步支持
首先,我们需要在Spring应用中开启异步支持。在XML配置中,可以通过在
<task:annotation-driven>
<task:executor id="myThreadPoolExecutor" pool-size="5"/>
<task:executor id="secondThreadPoolExecutor" pool-size="10"/>
<task:executor id="customAsyncExecutor" pool-size="20"/>
<task:async-method-executor task-executor="customAsyncExecutor"/>
<async/>
</task:annotation-driven>
在Java Config中,可以通过使用@EnableAsync注解开启异步支持。
@Configuration
@EnableAsync
public class AppConfig {
//其他配置
}
使用@Async注解实现异步方法
有了异步支持后,我们就可以在方法上添加@Async注解来实现异步方法。@Async注解发挥作用的前提是方法必须是public类型方法。
@Service
public class UserService{
@Async
public void longTimeOper(){
//xxxxxx
}
//其他代码
}
使用Future返回异步结果
如果需要获取异步方法的返回结果,可以在方法的返回类型上使用Java的Future类型。
@Service
public class UserService{
@Async
public Future<String> longTimeOperWithResult(){
//xxxxxx
return new AsyncResult<String>("result");
}
//其他代码
}
示例1:异步方法的实现
假设我们需要批量处理用户信息,并返回处理成功的用户数。首先,我们定义一个UserService:
@Service
public class UserService {
private static final Logger log = LoggerFactory.getLogger(UserService.class);
private static final Random random= new Random();
public int batchSaveUserList(List<User> users) throws InterruptedException {
for (User user : users) {
saveUser(user);
}
Thread.sleep(5000);//模拟保存数据需要5秒
return users.size();
}
@Async
public Future<Integer> batchSaveUserListAsync(List<User> users) throws InterruptedException {
return new AsyncResult<>(batchSaveUserList(users));
}
public void saveUser(User user) throws InterruptedException {
log.info("save user: {}", user);
Thread.sleep(random.nextInt(1000));
}
}
UserService中包含了两个方法batchSaveUserList和batchSaveUserListAsync,前者是同步方法,后者是异步方法。batchSaveUserList方法模拟需要花费5秒的数据保存操作,而saveUser方法模拟插入单个用户时的操作。
接下来,我们编写测试代码:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class UserServiceTest {
private static final Logger log = LoggerFactory.getLogger(UserServiceTest.class);
@Autowired
private UserService userService;
@Test
public void batchSaveUserTest() throws InterruptedException {
List<User> users = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
User user = new User();
user.setName("name_" + i);
user.setAge(20 + i);
users.add(user);
}
int size = userService.batchSaveUserList(users);
log.info("batchSaveUserList saved: {} records", size);
}
@Test
public void batchSaveUserAsyncTest() throws InterruptedException, ExecutionException {
List<User> users = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
User user = new User();
user.setName("name_" + i);
user.setAge(20 + i);
users.add(user);
}
Future<Integer> future = userService.batchSaveUserListAsync(users);
int size = future.get();
log.info("batchSaveUserAsync saved: {} records", size);
}
}
在测试代码中,我们分别调用了同步方法batchSaveUserList和异步方法batchSaveUserListAsync。执行结果表明异步方法可以提前返回,不必等到数据保存完成。
示例2:带参数的异步方法
为了更好地说明带参数的异步方法,我们假设初始化一个User对象需要5秒。此时,我们就可以使用异步方法initUser来异步初始化一个User对象:
@Service
public class UserService {
private static final Logger log = LoggerFactory.getLogger(UserService.class);
private static final Random random= new Random();
public User initUser() throws InterruptedException {
Thread.sleep(5000);//模拟初始化User需要5秒
User user = new User();
user.setName("user");
user.setAge(18);
return user;
}
@Async
public Future<User> initUserAsync() throws InterruptedException {
User user = initUser();
return new AsyncResult<>(user);
}
public void saveUser(User user) throws InterruptedException {
log.info("save user: {}", user);
Thread.sleep(random.nextInt(1000));
}
}
使用方式如下:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class UserServiceTest {
private static final Logger log = LoggerFactory.getLogger(UserServiceTest.class);
@Autowired
private UserService userService;
@Test
public void initUserTest() throws InterruptedException {
User user = userService.initUser();
userService.saveUser(user);
}
@Test
public void initUserAsyncTest() throws ExecutionException, InterruptedException {
Future<User> future = userService.initUserAsync();
User user = future.get();
userService.saveUser(user);
}
}
执行结果表明异步方法可以提前返回,不必等到User对象初始化完成。
至此,我们已经对Spring中的@Async用法进行了详细的讲解,并提供了两个实际应用的示例,相信能够帮助读者更好地理解和使用@Async注解。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring中@Async用法详解及简单实例 - Python技术站