1.异步调用简介
异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步一步执行,每一步必须等到上一步执行完成之后才能执行,而异步调用则无需等待上一步程序执行完成即可执行。在日常开发的项目中,当访问的接口较慢或者做耗时任务时,避免程序一直卡在耗时任务上,使程序能够并行执行,可以使用多线程来并行处理,也可以使用SpringBoot提供的异步处理方式@Async来处理。
2.引入依赖
新建一个SpringBoot工程,并在pom.xml文件中添加需要的dependency。
mysql
mysql-connector-java
org.springframework.boot
spring-boot-starter-jdbc
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.1.1
org.projectlombok
lombok
1.18.2
provided
3.添加配置
在application.properties文件中添加如下配置信息。
############################################################
#
# MySQL配置
#
############################################################
### 连接信息
spring.datasource.url = jdbc:mysql://localhost:3306/mydb
### 用户名
spring.datasource.username = root
### 密码
spring.datasource.password = admin123
### 驱动
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
############################################################
#
# MyBatis配置
#
############################################################
### po类存放目录
mybatis.type-aliases-package = com.leichuangkj.async.dao.po
### mapper(.xml)资源文件存放路径
mybatis.mapper-locations = classpath:mybatis/mapper/*.xml
spring.aop.proxy-target-class = true
4.dao层开发
首先在项目目录“/src/main/java/com/leichuangkj/async”下新建“/dao/po”目录,并在po目录下新建User实体类,具体代码如下。
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
private Integer id;
private String name;
private String email;
}
然后在dao目录下新建mapper目录,并在mapper目录下新建UserMapper接口,具体代码如下。
@Repository
public interface UserMapper {
List<User> findAll();
}
最后在resource目录下新建“mybatis/mapper”目录,并在mapper目录下新建UserMapper.xml文件,具体代码如下。
<mapper namespace="com.leichuangkj.async.dao.mapper.UserMapper" >
<resultMap id="BaseResultMap" type="com.leichuangkj.async.dao.po.User">
<constructor>
<idArg column="id" javaType="java.lang.Integer" jdbcType="INTEGER" />
<arg column="name" javaType="java.lang.String" jdbcType="VARCHAR" />
<arg column="email" javaType="java.lang.String" jdbcType="VARCHAR" />
constructor>
resultMap>
<select id="findAll" resultMap="BaseResultMap">
select id, name, email
from user
select>
mapper>
5.service层开发
在项目目录“/src/main/java/com/leichuangkj/async”下新建service目录,并在service目录下新建IUser接口,具体代码如下。
public interface IUser {
List<User> findAllSync() ;
Future<List<User>> findAllAsync();
}
然后在service目录下新建impl目录,并在impl目录下新建UserImpl实现类,具体代码如下。
@Service
public class UserImpl implements IUser {
@Autowired
UserMapper userMapper;
@Override
public List<User> findAllSync() {
try {
System.out.println("开始做任务");
long start = System.currentTimeMillis();
List<User> userList = userMapper.findAll();
long end = System.currentTimeMillis();
System.out.println("完成任务,耗时:" + (end - start)+"毫秒");
return userList;
}catch (Exception e){
return Collections.emptyList();
}
}
@Async
@Override
public Future<List<User>> findAllAsync() {
try {
System.out.println("开始做任务");
long start = System.currentTimeMillis();
List<User> userList = userMapper.findAll();
long end = System.currentTimeMillis();
System.out.println("完成任务,耗时:" + (end - start)+"毫秒");
return new AsyncResult<>(userList);
}catch (Exception e){
return new AsyncResult<>(null);
}
}
}
6.controller层开发
在项目目录“/src/main/java/com/leichuangkj/async”下新建controller目录,并在controller目录下新建UserController类,具体代码如下。
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
UserImpl userImpl;
@RequestMapping(value = "/findAllSync",method = RequestMethod.GET)
public void findAllSync(){
long start = System.currentTimeMillis();
System.out.println("第一次查询所有用户");
List<User> userList1 = userImpl.findAllSync();
System.out.println("第二次查询所有用户");
List<User> userList2 = userImpl.findAllSync();
System.out.println("第三次查询所有用户");
List<User> userList3 = userImpl.findAllSync();
long end = System.currentTimeMillis();
System.out.println("总共消耗:"+ (end - start) + "毫秒");
}
@RequestMapping(value = "/findAllAsync",method = RequestMethod.GET)
public void findAllAsync() throws InterruptedException {
long start = System.currentTimeMillis();
System.out.println("第一次查询所有用户");
Future<List<User>> userList1 = userImpl.findAllAsync();
System.out.println("第二次查询所有用户");
Future<List<User>> userList2 = userImpl.findAllAsync();
System.out.println("第三次查询所有用户");
Future<List<User>> userList3 = userImpl.findAllAsync();
while(true){
if(userList1.isDone()&&userList2.isDone()&&userList3.isDone()){
break;
}else{
Thread.sleep(10);
}
}
long end = System.currentTimeMillis();
System.out.println("总共消耗:"+ (end - start) + "毫秒");
}
}
7.启动项目
在启动类MyBatisApplication上添加注解“@MapperScan(basePackages = “com.leichuangkj.async.dao.mapper”)”和“@EnableAsync(proxyTargetClass = true)”,然后启动项目。
@MapperScan(basePackages = "com.leichuangkj.async.dao.mapper")
@SpringBootApplication
@EnableAsync(proxyTargetClass = true)
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
}
8.测试
启动项目,然后分别在postman中请求“http://localhost:8080/user/findAllSync”和“http://localhost:8080/user/findAllAsync”,可以在控制台看到相应的执行结果,测试结果如下图所示,可以看到同步执行三次查询耗时为988毫秒,异步执行三次查询耗时772毫秒,由此可见,异步调用速度比同步调用速度快。