天天看点

spring的@Async注解异步使用

一.异步简单介绍

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异步方法不再该包下才能避免被重复扫描。