一.异步简单介绍
1.Spring为任务调度与异步方法执行提供了注解支持。通过在方法上设置@Async注解,可使得方法被异步调用。也就是说调用者会在调用时立即返回,而被调用方法的实际执行是交给Spring的TaskExecutor来完成。
二. springboot+async异步接口实现和调用
1.maven依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2.代码小栗子
@Autowired
private AsyncTask asyncTask;
@Override
public void ImUserInsertEmployee(String strUserName,String strToken)throws Exception{
List<Integer> sysUserIdList = parkingAreaDao.selectSysUserIdList();
StringBuilder pathBuilder = new StringBuilder(FinalUtil.WEBSITE);
pathBuilder.append(FinalUtil.ORG_NAME);
pathBuilder.append("/");
pathBuilder.append(FinalUtil.APP_NAME);
pathBuilder.append("/users/");
pathBuilder.append(strUserName);
pathBuilder.append("/contacts/users/");
Map<String,Object> map = new HashMap<>();
map.put("owner_username",strUserName);
long currentTimeMillisTotalStart = System.currentTimeMillis();//
asyncTask.taskInterface(pathBuilder,map,sysUserIdList,strToken);
long currentTimeMillisTotalEnd = System.currentTimeMillis();//
long totalTime = currentTimeMillisTotalEnd - currentTimeMillisTotalStart;//
System.out.println("总请求耗時"+totalTime);//
}
@Component
public class AsyncTask {
@Async
public void taskInterface(StringBuilder pathBuilder, Map<String,Object> map,List<Integer> sysUserIdList,String strToken)throws Exception{
int i = 0;//
long currentTimeMillisTotalStart = System.currentTimeMillis();//
for(Integer sysUserId : sysUserIdList){
pathBuilder.append(sysUserId.toString());
map.put("friend_username",sysUserId.toString());
long currentTimeMillisStart = System.currentTimeMillis();//
HttpClientUtils.interfaceUtil(pathBuilder.toString(), JSONUtil.getJSONString(map), FinalUtil.REQUEST_METHOD.REQUEST_METHOD_POST, strToken);
long currentTimeMillisEnd = System.currentTimeMillis();//
pathBuilder.delete(pathBuilder.lastIndexOf("/")+1,pathBuilder.length());
long time = currentTimeMillisEnd-currentTimeMillisStart;//
System.out.println("第"+i+"次请求耗時"+time);//
i++;//
}
long currentTimeMillisTotalEnd = System.currentTimeMillis();//
long totalTime = currentTimeMillisTotalEnd - currentTimeMillisTotalStart;//
System.out.println("异步任务总请求耗時"+totalTime);//
}
}
3.springboot中 @async 无效原因:(1)在@SpringBootApplication启动类 添加注解@EnableAsync
(2)异步方法使用注解@Async ,返回值为void或者Future
(3)重点注意 ,异步方法和调用方法一定要写在不同的类中 ,如果写在一个类中,
是没有效果
二.springMVC开启@Async注解:
<task:annotation-driven executor="annotationExecutor" />
<!-- 支持 @Async 注解 -->
<task:executor id="annotationExecutor" pool-size="20"/>
同时加入<context:component-scan />扫描注解。其他跟上面是一样的。
@Async注解无效可能:注解扫描时,要注意过滤,避免重复实例化,因为存在覆盖问题,@Async就失效了,
举例,如果除了applicationContext.xml 中配置了包扫描外,还在dispatcher-Servlet.xml中还配置了包扫描。则会出现异步失效问题。
<context:component-scan base-package="com.xx.yy.*" />
解决方案:
1.在dispatcher-Servlet.xml 中指定扫描某个包
<context:component-scan base-package="com.xx.yy.controller" >
</context:component-scan>
实际上<context:component-scan> 有个属性use-default-filters它的默认值为true,那么会对base-package包或者子包下的所有的进行Java类进行扫描,并把@Component的类的java类注册成bean,所以还是不能避免异步方法所在类被重复扫描,如果需要指定一些包扫描,一些包不扫描,则需要修改Use-dafault-filter的默认值。Use-dafault-filters=”false”
只有@Async异步方法不再该包下才能避免被重复扫描。